public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* patch to fix
@ 2012-10-03 17:17 Kenneth Zadeck
  2012-10-03 20:47 ` Marc Glisse
  2012-10-04 12:48 ` Richard Guenther
  0 siblings, 2 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-03 17:17 UTC (permalink / raw)
  To: Kenneth Zadeck, Mike Stump, Richard Sandiford, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 8916 bytes --]

The enclosed patch is the third of at least four patches that fix the
problems associated with supporting integers on the target that are
wider than two HOST_WIDE_INTs.

While GCC claims to support OI mode, and we have two public ports that
make minor use of this mode, in practice, compilation that uses OImode
mode commonly gives the wrong result or ices.  We have a private port
of GCC for an architecture that is further down the road to needing
comprehensive OImode and we have discovered that this is unusable. We
have decided to fix it in a general way that so that it is most
beneficial to the GCC community.  It is our belief that we are just a
little ahead of the X86 and the NEON and these patches will shortly be
essential.

The first two of these patches were primarily lexigraphical and have
already been committed.    They transformed the uses of CONST_DOUBLE
so that it is easy to tell what the intended usage is.

The underlying structures in the next two patches are very general:
once they are added to the compiler, the compiler will be able to
support targets with any size of integer from hosts of any size
integer.

The patch enclosed deals with the portable RTL parts of the compiler.
The next patch, which is currently under construction deals with the
tree level.  However, this patch can be put on the trunk as is, and it
will eleviate many, but not all of the current limitations in the rtl
parts of the compiler.

Some of the patch is conditional, depending on a port defining the
symbol 'TARGET_SUPPORTS_WIDE_INT' to be non zero.  Defining this
symbol to be non zero is declaring that the port has been converted to
use the new form or integer constants.  However, the patch is
completely backwards compatible to allow ports that do not need this
immediately to convert at their leasure.  The conversion process is
not difficult, but it does require some knowledge of the port, so we
are not volinteering to do this for all ports.

OVERVIEW OF THE PATCH:

The patch defines a new datatype, a 'wide_int' (defined in
wide-int.[ch], and this datatype will be used to perform all of the
integer constant math in the compiler.  Externally, wide-int is very
similar to double-int except that it does not have the limitation that
math must be done on exactly two HOST_WIDE_INTs.

Internally, a wide_int is a structure that contains a fixed sized
array of HOST_WIDE_INTs, a length field and a mode.  The size of the
array is determined at generation time by dividing the number of bits
of the largest integer supported on the target by the number of bits
in a HOST_WIDE_INT of the host.  Thus, with this format, any length of
integer can be supported on any host.

A new rtx type is created, the CONST_WIDE_INT, which contains a
garbage collected array of HOST_WIDE_INTS that is large enough to hold
the constant.  For the targets that define TARGET_SUPPORTS_WIDE_INT to
be non zero, CONST_DOUBLES are only used to hold floating point
values.  If the target leaves TARGET_SUPPORTS_WIDE_INT defined as 0,
CONST_WIDE_INTs are not used and CONST_DOUBLEs are as they were
before.

CONST_INT does not change except that it is defined to hold all
constants that fit in exactly one HOST_WIDE_INT.  Note that is slightly
different than the current trunk.  Before this patch, the TImode
constant '5' could either be in a CONST_INT or CONST_DOUBLE depending
on which code path was used to create it.  This patch changes this so
that if the constant fits in a CONST_INT then it is represented in a
CONST_INT no matter how it is created.

For the array inside a CONST_WIDE_INT, and internally in wide-int, we
use a compressed form for integers that need more than one
HOST_WIDE_INT.  Higher elements of the array are not needed if they
are just a sign extension of the elements below them.  This does not
imply that constants are signed or are sign extended, this is only a
compression technique.

While it might seem to be more esthetically pleasing to have not
introduced the CONST_WIDE_INT and to have changed the representation
of the CONST_INT to accomodate larger numbers, this would have both
used more space and would be a time consuming change for the port
maintainers.  We believe that most ports can be quickly converted with
the current scheme because there is just not a lot of code in the back
ends that cares about large constants.  Furthermore, the CONST_INT is
very space efficient and even in a program that was heavy in large
values, most constants would still fit in a CONST_INT.

All of the parts of the rtl level that deal with CONST_DOUBLE as an
now conditionally work with CONST_WIDE_INTs depending on the value
of TARGET_SUPPORTS_WIDE_INT.  We believe that this patch removes all
of the ices and wrong code places at the portable rtl level. However,
there are still places in the portable rtl code that refuse to
transform the code unless it is a CONST_INT.  Since these do not cause
failures, they can be handled later.  The patch is already very large.

It should be noted that much of the constant overflow checking in the
constant math dissappears with these patches.  The overflow checking
code in the current compiler is really divided into two cases:
overflow on the host and overflow on the target.  The overflow
checking on the host was to make sure that the math did overflow when
done on two HOST_WIDE_INTs.  All of this code goes away.  These
patches allow the constant math to be done exactly the way it is done
on the target.

This patch also aids other cleanups that are being considered at the
rtl level:

   1) These patches remove most of the host dependencies on the
   optimizations.  Currently a 32 bit GCC host will produce different
   code for a specific target than a 64 bit host will.  This is because
   many of the transformations only work on constants that can be a
   represented with a single HWI or two HWIs.  If the target has larger
   integers than the host, the compilation suffers.

   2) Bernd's need to make GCC correctly support partial its is made
   easier by the wide-int library.  This library carefully does all
   arithmetic in the precision of the mode included in it.  While there
   are still places at the rtl level that still do arithmetic inline,
   we plan to convert those to use the library over time.   This patch
   converts a substantial number of those places.

   3) This patch is one step along the path to add modes to rtl integer
   constants.  There is no longer any checking to see if a CONST_DOUBLE
   has VOIDmode as its mode.  Furthermore, all constructors for various
   wide ints do take a mode and require that it not be VOIDmode. There
   is still a lot of work to do to make this conversion possible.

Richard Sandiford has been over the rtl portions of this patch a few
times.  He has not looked at the wide-int files in any detail.  This
patch has been heavily tested on my private ports and also on x86-64.


CONVERSION PROCESS

Converting a port mostly requires looking for the places where
CONST_DOUBLES are used with VOIDmode and replacing that code with code
that accesses CONST_WIDE_INTs.  "grep -i const_double" at the port
level gets you to 95% of the changes that need to be made.  There are
a few places that require a deeper look.

   1) There is no equivalent to hval and lval for CONST_WIDE_INTs.
   This would be difficult to express in the md language since there
   are a variable number of elements.

   Most ports only check that hval is either 0 or -1 to see if the int
   is small.  As mentioned above, this will no longer be necessary
   since small constants are always CONST_INT.  Of course there are
   still a few exceptions, the alpha's constraint used by the zap
   instruction certainly requires careful examination by C code.
   However, all the current code does is pass the hval and lval to C
   code, so evolving the c code to look at the CONST_WIDE_INT is not
   really a large change.

   2) Because there is no standard template that ports use to
   materialize constants, there is likely to be some futzing that is
   unique to each port in this code.

   3) The rtx costs may have to be adjusted to properly account for
   larger constants that are represented as CONST_WIDE_INT.

All and all it has not taken us long to convert ports that we are
familiar with.

OTHER COMMENTS

I did find what i believe is one interesting bug in the double-int
code.  I believe that the code that performs divide and mod with round
to nearest is seriously wrong for unsigned integers.  I believe that
it will get the wrong answer for any numbers that are large enough to
look negative if they consider signed integers.  Asside from that,
wide-int should perform in a very similar manner to double-int.

I am sorry for the size of this patch.   However, there does not appear
to change the underlying data structure to support wider integers
without doing something like this.

kenny

[-- Attachment #2: rtl3.diff --]
[-- Type: text/x-patch, Size: 274911 bytes --]

Index: gcc/reload.c
===================================================================
--- gcc/reload.c	(revision 191978)
+++ gcc/reload.c	(working copy)
@@ -3437,7 +3437,7 @@ find_reloads (rtx insn, int replace, int
 		    break;
 
 		  case 's':
-		    if (CONST_INT_P (operand) || CONST_DOUBLE_AS_INT_P (operand))
+		    if (CONST_SCALAR_INT_P (operand))
 		      break;
 		  case 'i':
 		    if (CONSTANT_P (operand)
@@ -3446,7 +3446,7 @@ find_reloads (rtx insn, int replace, int
 		    break;
 
 		  case 'n':
-		    if (CONST_INT_P (operand) || CONST_DOUBLE_AS_INT_P (operand))
+		    if (CONST_SCALAR_INT_P (operand))
 		      win = 1;
 		    break;
 
Index: gcc/rtl.def
===================================================================
--- gcc/rtl.def	(revision 191978)
+++ gcc/rtl.def	(working copy)
@@ -319,6 +319,9 @@ DEF_RTL_EXPR(TRAP_IF, "trap_if", "ee", R
 /* numeric integer constant */
 DEF_RTL_EXPR(CONST_INT, "const_int", "w", RTX_CONST_OBJ)
 
+/* numeric integer constant */
+DEF_RTL_EXPR(CONST_WIDE_INT, "const_wide_int", "", RTX_CONST_OBJ)
+
 /* fixed-point constant */
 DEF_RTL_EXPR(CONST_FIXED, "const_fixed", "www", RTX_CONST_OBJ)
 
Index: gcc/ira-costs.c
===================================================================
--- gcc/ira-costs.c	(revision 191978)
+++ gcc/ira-costs.c	(working copy)
@@ -667,7 +667,7 @@ record_reg_classes (int n_alts, int n_op
 		  break;
 
 		case 's':
-		  if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op)) 
+		  if (CONST_SCALAR_INT_P (op)) 
 		    break;
 
 		case 'i':
@@ -677,7 +677,7 @@ record_reg_classes (int n_alts, int n_op
 		  break;
 
 		case 'n':
-		  if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op)) 
+		  if (CONST_SCALAR_INT_P (op)) 
 		    win = 1;
 		  break;
 
@@ -1068,7 +1068,7 @@ record_address_regs (enum machine_mode m
 
 	/* If the second operand is a constant integer, it doesn't
 	   change what class the first operand must be.  */
-	else if (code1 == CONST_INT || code1 == CONST_DOUBLE)
+	else if (CONST_SCALAR_INT_P (arg1))
 	  record_address_regs (mode, as, arg0, context, PLUS, code1, scale);
 	/* If the second operand is a symbolic constant, the first
 	   operand must be an index register.  */
Index: gcc/dojump.c
===================================================================
--- gcc/dojump.c	(revision 191978)
+++ gcc/dojump.c	(working copy)
@@ -144,6 +144,7 @@ static bool
 prefer_and_bit_test (enum machine_mode mode, int bitnum)
 {
   bool speed_p;
+  wide_int mask = wide_int::set_bit_in_zero (bitnum, mode);
 
   if (and_test == 0)
     {
@@ -164,8 +165,7 @@ prefer_and_bit_test (enum machine_mode m
     }
 
   /* Fill in the integers.  */
-  XEXP (and_test, 1)
-    = immed_double_int_const (double_int_zero.set_bit (bitnum), mode);
+  XEXP (and_test, 1) = immed_wide_int_const (mask);
   XEXP (XEXP (shift_test, 0), 1) = GEN_INT (bitnum);
 
   speed_p = optimize_insn_for_speed_p ();
Index: gcc/recog.c
===================================================================
--- gcc/recog.c	(revision 191978)
+++ gcc/recog.c	(working copy)
@@ -586,8 +586,7 @@ simplify_while_replacing (rtx *loc, rtx
 			 (PLUS, GET_MODE (x), XEXP (x, 0), XEXP (x, 1)), 1);
       break;
     case MINUS:
-      if (CONST_INT_P (XEXP (x, 1))
-	  || CONST_DOUBLE_AS_INT_P (XEXP (x, 1)))
+      if (CONST_SCALAR_INT_P (XEXP (x, 1)))
 	validate_change (object, loc,
 			 simplify_gen_binary
 			 (PLUS, GET_MODE (x), XEXP (x, 0),
@@ -1146,6 +1145,86 @@ const_int_operand (rtx op, enum machine_
   return 1;
 }
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns 1 if OP is an operand that is a CONST_INT or CONST_WIDE_INT.  */
+int
+const_scalar_int_operand (rtx op, enum machine_mode mode)
+{
+  if (!CONST_WIDE_INT_P (op))
+    return 0;
+
+  if (mode != VOIDmode)
+    {
+      int prec = GET_MODE_PRECISION (mode);
+      int bitsize = GET_MODE_BITSIZE (mode);
+      
+      if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
+	return 0;
+      
+      if (prec == bitsize)
+	return 1;
+      else
+	{
+	  /* Multiword partial int.  */
+	  HOST_WIDE_INT x 
+	    = CONST_WIDE_INT_ELT (op, CONST_WIDE_INT_NUNITS (op) - 1);
+	  return (wide_int::sext (x, prec & (HOST_BITS_PER_WIDE_INT - 1))
+		  == x);
+	}
+    }
+  return 1;
+}
+
+/* Returns 1 if OP is an operand that is a CONST_WIDE_INT.  */
+int
+const_wide_int_operand (rtx op, enum machine_mode mode)
+{
+  switch (GET_CODE (op)) 
+    {
+    case CONST_INT:
+      if (mode != VOIDmode
+	  && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
+	return 0;
+      return 1;
+
+    case CONST_WIDE_INT:
+      if (mode != VOIDmode)
+	{
+	  int prec = GET_MODE_PRECISION (mode);
+	  int bitsize = GET_MODE_BITSIZE (mode);
+
+	  if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
+	    return 0;
+
+	  if (prec == bitsize)
+	    return 1;
+	  else
+	    {
+	      /* Multiword partial int.  */
+	      HOST_WIDE_INT x
+		= CONST_WIDE_INT_ELT (op, CONST_WIDE_INT_NUNITS (op));
+	      return (wide_int::sext (x,
+				      prec & (HOST_BITS_PER_WIDE_INT - 1))
+		      == x);
+	    }
+	}
+      return 1;
+
+    default:
+      return 0;
+    }
+}
+
+/* Returns 1 if OP is an operand that is a constant integer or constant
+   floating-point number.  */
+
+int
+const_double_operand (rtx op, enum machine_mode mode)
+{
+  return (GET_CODE (op) == CONST_DOUBLE)
+	  && (GET_MODE (op) == mode || mode == VOIDmode);
+}
+#else
 /* Returns 1 if OP is an operand that is a constant integer or constant
    floating-point number.  */
 
@@ -1163,7 +1242,7 @@ const_double_operand (rtx op, enum machi
 	  && (mode == VOIDmode || GET_MODE (op) == mode
 	      || GET_MODE (op) == VOIDmode));
 }
-
+#endif
 /* Return 1 if OP is a general operand that is not an immediate operand.  */
 
 int
@@ -1726,7 +1805,7 @@ asm_operand_ok (rtx op, const char *cons
 	  break;
 
 	case 's':
-	  if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+	  if (CONST_SCALAR_INT_P (op))
 	    break;
 	  /* Fall through.  */
 
@@ -1736,7 +1815,7 @@ asm_operand_ok (rtx op, const char *cons
 	  break;
 
 	case 'n':
-	  if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+	  if (CONST_SCALAR_INT_P (op))
 	    result = 1;
 	  break;
 
@@ -2591,7 +2670,7 @@ constrain_operands (int strict)
 		break;
 
 	      case 's':
-		if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+		if (CONST_SCALAR_INT_P (op))
 		  break;
 	      case 'i':
 		if (CONSTANT_P (op))
@@ -2599,7 +2678,7 @@ constrain_operands (int strict)
 		break;
 
 	      case 'n':
-		if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+		if (CONST_SCALAR_INT_P (op))
 		  win = 1;
 		break;
 
Index: gcc/rtl.c
===================================================================
--- gcc/rtl.c	(revision 191978)
+++ gcc/rtl.c	(working copy)
@@ -111,7 +111,7 @@ const enum rtx_class rtx_class[NUM_RTX_C
 const unsigned char rtx_code_size[NUM_RTX_CODE] = {
 #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)				\
   (((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE			\
-    || (ENUM) == CONST_FIXED)						\
+    || (ENUM) == CONST_FIXED || (ENUM) == CONST_WIDE_INT)		\
    ? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT)	\
    : RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (rtunion)),
 
@@ -183,18 +183,24 @@ shallow_copy_rtvec (rtvec vec)
 unsigned int
 rtx_size (const_rtx x)
 {
+  if (GET_CODE (x) == CONST_WIDE_INT)
+    return (RTX_HDR_SIZE
+	    + sizeof (struct hwivec_def)
+	    + ((CONST_WIDE_INT_NUNITS (x) - 1)
+	       * sizeof (HOST_WIDE_INT)));
   if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_HAS_BLOCK_INFO_P (x))
     return RTX_HDR_SIZE + sizeof (struct block_symbol);
   return RTX_CODE_SIZE (GET_CODE (x));
 }
 
-/* Allocate an rtx of code CODE.  The CODE is stored in the rtx;
-   all the rest is initialized to zero.  */
+/* Allocate an rtx of code CODE with EXTRA bytes in it.  The CODE is
+   stored in the rtx; all the rest is initialized to zero.  */
 
 rtx
-rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
+rtx_alloc_stat_v (RTX_CODE code MEM_STAT_DECL, int extra)
 {
-  rtx rt = ggc_alloc_zone_rtx_def_stat (&rtl_zone, RTX_CODE_SIZE (code)
+  rtx rt = ggc_alloc_zone_rtx_def_stat (&rtl_zone,
+					RTX_CODE_SIZE (code) + extra
                                         PASS_MEM_STAT);
 
   /* We want to clear everything up to the FLD array.  Normally, this
@@ -213,6 +219,29 @@ rtx_alloc_stat (RTX_CODE code MEM_STAT_D
   return rt;
 }
 
+/* Allocate an rtx of code CODE.  The CODE is stored in the rtx;
+   all the rest is initialized to zero.  */
+
+rtx
+rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
+{
+  return rtx_alloc_stat_v (code PASS_MEM_STAT, 0);
+}
+
+/* Write the wide constant OP0 to OUTFILE.  */
+
+void
+hwivec_output_hex (FILE *outfile, const_hwivec op0)
+{
+  int i = HWI_GET_NUM_ELEM (op0);
+  gcc_assert (i > 0);
+  if (XHWIVEC_ELT (op0, i-1) == 0)
+    fprintf (outfile, "0x");
+  fprintf (outfile, HOST_WIDE_INT_PRINT_HEX, XHWIVEC_ELT (op0, --i));
+  while (--i >= 0)
+    fprintf (outfile, HOST_WIDE_INT_PRINT_PADDED_HEX, XHWIVEC_ELT (op0, i));
+}
+
 \f
 /* Return true if ORIG is a sharable CONST.  */
 
@@ -427,7 +456,6 @@ rtx_equal_p_cb (const_rtx x, const_rtx y
 	  if (XWINT (x, i) != XWINT (y, i))
 	    return 0;
 	  break;
-
 	case 'n':
 	case 'i':
 	  if (XINT (x, i) != XINT (y, i))
@@ -645,6 +673,10 @@ iterative_hash_rtx (const_rtx x, hashval
       return iterative_hash_object (i, hash);
     case CONST_INT:
       return iterative_hash_object (INTVAL (x), hash);
+    case CONST_WIDE_INT:
+      for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	hash = iterative_hash_object (CONST_WIDE_INT_ELT (x, i), hash);
+      return hash;
     case SYMBOL_REF:
       if (XSTR (x, 0))
 	return iterative_hash (XSTR (x, 0), strlen (XSTR (x, 0)) + 1,
@@ -809,6 +841,16 @@ rtl_check_failed_block_symbol (const cha
 }
 
 /* XXX Maybe print the vector?  */
+void
+hwivec_check_failed_bounds (const_hwivec r, int n, const char *file, int line,
+			    const char *func)
+{
+  internal_error
+    ("RTL check: access of hwi elt %d of vector with last elt %d in %s, at %s:%d",
+     n, GET_NUM_ELEM (r) - 1, func, trim_filename (file), line);
+}
+
+/* XXX Maybe print the vector?  */
 void
 rtvec_check_failed_bounds (const_rtvec r, int n, const char *file, int line,
 			   const char *func)
Index: gcc/rtl.h
===================================================================
--- gcc/rtl.h	(revision 191978)
+++ gcc/rtl.h	(working copy)
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.
 #include "fixed-value.h"
 #include "alias.h"
 #include "hashtab.h"
+#include "wide-int.h"
 #include "flags.h"
 
 /* Value used by some passes to "recognize" noop moves as valid
@@ -252,6 +253,14 @@ struct GTY(()) object_block {
   VEC(rtx,gc) *anchors;
 };
 
+struct GTY((variable_size)) hwivec_def {
+  int num_elem;		/* number of elements */
+  HOST_WIDE_INT elem[1];
+};
+
+#define HWI_GET_NUM_ELEM(HWIVEC)	((HWIVEC)->num_elem)
+#define HWI_PUT_NUM_ELEM(HWIVEC, NUM)	((HWIVEC)->num_elem = (NUM))
+
 /* RTL expression ("rtx").  */
 
 struct GTY((chain_next ("RTX_NEXT (&%h)"),
@@ -344,6 +353,7 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"
     struct block_symbol block_sym;
     struct real_value rv;
     struct fixed_value fv;
+    struct hwivec_def hwiv;
   } GTY ((special ("rtx_def"), desc ("GET_CODE (&%0)"))) u;
 };
 
@@ -382,13 +392,13 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"
    for a variable number of things.  The principle use is inside
    PARALLEL expressions.  */
 
+#define NULL_RTVEC (rtvec) 0
+
 struct GTY((variable_size)) rtvec_def {
   int num_elem;		/* number of elements */
   rtx GTY ((length ("%h.num_elem"))) elem[1];
 };
 
-#define NULL_RTVEC (rtvec) 0
-
 #define GET_NUM_ELEM(RTVEC)		((RTVEC)->num_elem)
 #define PUT_NUM_ELEM(RTVEC, NUM)	((RTVEC)->num_elem = (NUM))
 
@@ -398,12 +408,38 @@ struct GTY((variable_size)) rtvec_def {
 /* Predicate yielding nonzero iff X is an rtx for a memory location.  */
 #define MEM_P(X) (GET_CODE (X) == MEM)
 
+#if TARGET_SUPPORTS_WIDE_INT
+
+/* Match CONST_*s that can represent compile-time constant integers.  */
+#define CASE_CONST_SCALAR_INT \
+   case CONST_INT: \
+   case CONST_WIDE_INT
+
+/* Match CONST_*s for which pointer equality corresponds to value 
+   equality.  */
+#define CASE_CONST_UNIQUE \
+   case CONST_INT: \
+   case CONST_WIDE_INT: \
+   case CONST_DOUBLE: \
+   case CONST_FIXED
+
+/* Match all CONST_* rtxes.  */
+#define CASE_CONST_ANY \
+   case CONST_INT: \
+   case CONST_WIDE_INT: \
+   case CONST_DOUBLE: \
+   case CONST_FIXED: \
+   case CONST_VECTOR
+
+#else
+
 /* Match CONST_*s that can represent compile-time constant integers.  */
 #define CASE_CONST_SCALAR_INT \
    case CONST_INT: \
    case CONST_DOUBLE
 
-/* Match CONST_*s for which pointer equality corresponds to value equality.  */
+/* Match CONST_*s for which pointer equality corresponds to value 
+equality.  */
 #define CASE_CONST_UNIQUE \
    case CONST_INT: \
    case CONST_DOUBLE: \
@@ -415,10 +451,17 @@ struct GTY((variable_size)) rtvec_def {
    case CONST_DOUBLE: \
    case CONST_FIXED: \
    case CONST_VECTOR
+#endif
+
+
+
 
 /* Predicate yielding nonzero iff X is an rtx for a constant integer.  */
 #define CONST_INT_P(X) (GET_CODE (X) == CONST_INT)
 
+/* Predicate yielding nonzero iff X is an rtx for a constant integer.  */
+#define CONST_WIDE_INT_P(X) (GET_CODE (X) == CONST_WIDE_INT)
+
 /* Predicate yielding nonzero iff X is an rtx for a constant fixed-point.  */
 #define CONST_FIXED_P(X) (GET_CODE (X) == CONST_FIXED)
 
@@ -430,6 +473,15 @@ struct GTY((variable_size)) rtvec_def {
 #define CONST_DOUBLE_AS_INT_P(X) \
   (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == VOIDmode)
 
+/* Predicate yielding true iff X is an rtx for a integer const.  */
+#if TARGET_SUPPORTS_WIDE_INT
+#define CONST_SCALAR_INT_P(X) \
+  (CONST_INT_P (X) || CONST_WIDE_INT_P (X))
+#else
+#define CONST_SCALAR_INT_P(X) \
+  (CONST_INT_P (X) || CONST_DOUBLE_AS_INT_P (X))
+#endif
+
 /* Predicate yielding true iff X is an rtx for a double-int.  */
 #define CONST_DOUBLE_AS_FLOAT_P(X) \
   (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode)
@@ -591,6 +643,13 @@ struct GTY((variable_size)) rtvec_def {
 			       __FUNCTION__);				\
      &_rtx->u.hwint[_n]; }))
 
+#define XHWIVEC_ELT(HWIVEC, I) __extension__				\
+(*({ __typeof (HWIVEC) const _hwivec = (HWIVEC); const int _i = (I);	\
+     if (_i < 0 || _i >= HWI_GET_NUM_ELEM (_hwivec))			\
+       hwivec_check_failed_bounds (_hwivec, _i, __FILE__, __LINE__,	\
+				  __FUNCTION__);			\
+     &_hwivec->elem[_i]; }))
+
 #define XCWINT(RTX, N, C) __extension__					\
 (*({ __typeof (RTX) const _rtx = (RTX);					\
      if (GET_CODE (_rtx) != (C))					\
@@ -627,6 +686,11 @@ struct GTY((variable_size)) rtvec_def {
 				    __FUNCTION__);			\
    &_symbol->u.block_sym; })
 
+#define HWIVEC_CHECK(RTX,C) __extension__				\
+({ __typeof (RTX) const _symbol = (RTX);				\
+   RTL_CHECKC1 (_symbol, 0, C);						\
+   &_symbol->u.hwiv; })
+
 extern void rtl_check_failed_bounds (const_rtx, int, const char *, int,
 				     const char *)
     ATTRIBUTE_NORETURN;
@@ -647,6 +711,9 @@ extern void rtl_check_failed_code_mode (
     ATTRIBUTE_NORETURN;
 extern void rtl_check_failed_block_symbol (const char *, int, const char *)
     ATTRIBUTE_NORETURN;
+extern void hwivec_check_failed_bounds (const_rtvec, int, const char *, int,
+					const char *)
+    ATTRIBUTE_NORETURN;
 extern void rtvec_check_failed_bounds (const_rtvec, int, const char *, int,
 				       const char *)
     ATTRIBUTE_NORETURN;
@@ -659,12 +726,14 @@ extern void rtvec_check_failed_bounds (c
 #define RTL_CHECKC2(RTX, N, C1, C2) ((RTX)->u.fld[N])
 #define RTVEC_ELT(RTVEC, I)	    ((RTVEC)->elem[I])
 #define XWINT(RTX, N)		    ((RTX)->u.hwint[N])
+#define XHWIVEC_ELT(HWIVEC, I)	    ((HWIVEC)->elem[I])
 #define XCWINT(RTX, N, C)	    ((RTX)->u.hwint[N])
 #define XCMWINT(RTX, N, C, M)	    ((RTX)->u.hwint[N])
 #define XCNMWINT(RTX, N, C, M)	    ((RTX)->u.hwint[N])
 #define XCNMPRV(RTX, C, M)	    (&(RTX)->u.rv)
 #define XCNMPFV(RTX, C, M)	    (&(RTX)->u.fv)
 #define BLOCK_SYMBOL_CHECK(RTX)	    (&(RTX)->u.block_sym)
+#define HWIVEC_CHECK(RTX,C)	    (&(RTX)->u.hwiv)
 
 #endif
 
@@ -807,8 +876,8 @@ extern void rtl_check_failed_flag (const
 #define XCCFI(RTX, N, C)      (RTL_CHECKC1 (RTX, N, C).rt_cfi)
 #define XCCSELIB(RTX, N, C)   (RTL_CHECKC1 (RTX, N, C).rt_cselib)
 
-#define XCVECEXP(RTX, N, M, C)	RTVEC_ELT (XCVEC (RTX, N, C), M)
-#define XCVECLEN(RTX, N, C)	GET_NUM_ELEM (XCVEC (RTX, N, C))
+#define XCVECEXP(RTX, N, M, C) RTVEC_ELT (XCVEC (RTX, N, C), M)
+#define XCVECLEN(RTX, N, C)    GET_NUM_ELEM (XCVEC (RTX, N, C))
 
 #define XC2EXP(RTX, N, C1, C2)      (RTL_CHECKC2 (RTX, N, C1, C2).rt_rtx)
 \f
@@ -1150,9 +1219,19 @@ rhs_regno (const_rtx x)
 #define INTVAL(RTX) XCWINT(RTX, 0, CONST_INT)
 #define UINTVAL(RTX) ((unsigned HOST_WIDE_INT) INTVAL (RTX))
 
+/* For a CONST_WIDE_INT, CONST_WIDE_INT_NUNITS is the number of
+   elements actually needed to represent the constant.
+   CONST_WIDE_INT_ELT gets one of the elements.  0 is the least
+   significant HOST_WIDE_INT.  */
+#define CONST_WIDE_INT_VEC(RTX) HWIVEC_CHECK (RTX, CONST_WIDE_INT)
+#define CONST_WIDE_INT_NUNITS(RTX) HWI_GET_NUM_ELEM (CONST_WIDE_INT_VEC (RTX))
+#define CONST_WIDE_INT_ELT(RTX, N) XHWIVEC_ELT (CONST_WIDE_INT_VEC (RTX), N) 
+
 /* For a CONST_DOUBLE:
+#if TARGET_SUPPORTS_WIDE_INT == 0
    For a VOIDmode, there are two integers CONST_DOUBLE_LOW is the
      low-order word and ..._HIGH the high-order.
+#endif
    For a float, there is a REAL_VALUE_TYPE structure, and
      CONST_DOUBLE_REAL_VALUE(r) is a pointer to it.  */
 #define CONST_DOUBLE_LOW(r) XCMWINT (r, 0, CONST_DOUBLE, VOIDmode)
@@ -1678,6 +1757,12 @@ extern rtx plus_constant (enum machine_m
 /* In rtl.c */
 extern rtx rtx_alloc_stat (RTX_CODE MEM_STAT_DECL);
 #define rtx_alloc(c) rtx_alloc_stat (c MEM_STAT_INFO)
+extern rtx rtx_alloc_stat_v (RTX_CODE MEM_STAT_DECL, int);
+#define rtx_alloc_v(c, SZ) rtx_alloc_stat_v (c MEM_STAT_INFO, SZ)
+#define const_wide_int_alloc(NWORDS)				\
+  rtx_alloc_v (CONST_WIDE_INT,					\
+	       (sizeof (struct hwivec_def)			\
+		+ ((NWORDS)-1) * sizeof (HOST_WIDE_INT)))	\
 
 extern rtvec rtvec_alloc (int);
 extern rtvec shallow_copy_rtvec (rtvec);
@@ -1734,10 +1819,17 @@ extern void start_sequence (void);
 extern void push_to_sequence (rtx);
 extern void push_to_sequence2 (rtx, rtx);
 extern void end_sequence (void);
+#if TARGET_SUPPORTS_WIDE_INT == 0
 extern double_int rtx_to_double_int (const_rtx);
-extern rtx immed_double_int_const (double_int, enum machine_mode);
+#endif
+extern void hwivec_output_hex (FILE *, const_hwivec);
+#ifndef GENERATOR_FILE
+extern rtx immed_wide_int_const (const wide_int &cst);
+#endif
+#if TARGET_SUPPORTS_WIDE_INT == 0
 extern rtx immed_double_const (HOST_WIDE_INT, HOST_WIDE_INT,
 			       enum machine_mode);
+#endif
 
 /* In loop-iv.c  */
 
Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c	(revision 191978)
+++ gcc/rtlanal.c	(working copy)
@@ -3081,6 +3081,8 @@ commutative_operand_precedence (rtx op)
   /* Constants always come the second operand.  Prefer "nice" constants.  */
   if (code == CONST_INT)
     return -8;
+  if (code == CONST_WIDE_INT)
+    return -8;
   if (code == CONST_DOUBLE)
     return -7;
   if (code == CONST_FIXED)
@@ -3093,6 +3095,8 @@ commutative_operand_precedence (rtx op)
     case RTX_CONST_OBJ:
       if (code == CONST_INT)
         return -6;
+      if (code == CONST_WIDE_INT)
+        return -6;
       if (code == CONST_DOUBLE)
         return -5;
       if (code == CONST_FIXED)
@@ -5351,6 +5355,20 @@ split_double (rtx value, rtx *first, rtx
 	    }
 	}
     }
+  else if (GET_CODE (value) == CONST_WIDE_INT)
+    {
+      gcc_assert (CONST_WIDE_INT_NUNITS (value) == 2);
+      if (WORDS_BIG_ENDIAN)
+	{
+	  *first = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+	  *second = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+	}
+      else
+	{
+	  *first = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+	  *second = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+	}
+    }
   else if (!CONST_DOUBLE_P (value))
     {
       if (WORDS_BIG_ENDIAN)
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 191978)
+++ gcc/Makefile.in	(working copy)
@@ -841,7 +841,7 @@ COMMON_TARGET_DEF_H = common/common-targ
 RTL_BASE_H = coretypes.h rtl.h rtl.def $(MACHMODE_H) reg-notes.def \
   insn-notes.def $(INPUT_H) $(REAL_H) statistics.h $(VEC_H) \
   $(FIXED_VALUE_H) alias.h $(HASHTAB_H)
-FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h
+FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h wide-int.h
 RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h vecir.h
 RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H)
 READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
@@ -853,7 +853,7 @@ INTERNAL_FN_H = internal-fn.h $(INTERNAL
 TREE_H = coretypes.h tree.h all-tree.def tree.def c-family/c-common.def \
 	$(lang_tree_files) $(MACHMODE_H) tree-check.h $(BUILTINS_DEF) \
 	$(INPUT_H) statistics.h $(VEC_H) treestruct.def $(HASHTAB_H) \
-	double-int.h alias.h $(SYMTAB_H) $(FLAGS_H) vecir.h \
+	double-int.h wide-int.h alias.h $(SYMTAB_H) $(FLAGS_H) vecir.h \
 	$(REAL_H) $(FIXED_VALUE_H)
 REGSET_H = regset.h $(BITMAP_H) hard-reg-set.h
 BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) \
@@ -1432,6 +1432,7 @@ OBJS = \
 	varpool.o \
 	vmsdbgout.o \
 	web.o \
+	wide-int.o \
 	xcoffout.o \
 	$(out_object_file) \
 	$(EXTRA_OBJS) \
@@ -2639,6 +2640,7 @@ targhooks.o : targhooks.c $(CONFIG_H) $(
    tree-ssa-alias.h $(TREE_FLOW_H)
 common/common-targhooks.o : common/common-targhooks.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(INPUT_H) $(TM_H) $(COMMON_TARGET_H) common/common-targhooks.h
+wide-int.o: wide-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
 
 bversion.h: s-bversion; @true
 s-bversion: BASE-VER
@@ -3833,15 +3835,16 @@ CFLAGS-gengtype-parse.o += -DGENERATOR_F
 build/gengtype-parse.o: $(BCONFIG_H)
 
 gengtype-state.o build/gengtype-state.o: gengtype-state.c $(SYSTEM_H) \
-  gengtype.h errors.h double-int.h version.h $(HASHTAB_H) $(OBSTACK_H) \
-  $(XREGEX_H)
+  gengtype.h errors.h double-int.h wide-int.h version.h $(HASHTAB_H)    \
+  $(OBSTACK_H) $(XREGEX_H)
 gengtype-state.o: $(CONFIG_H)
 CFLAGS-gengtype-state.o += -DGENERATOR_FILE
 build/gengtype-state.o: $(BCONFIG_H)
+wide-int.h: $(GTM_H) insn-modes.h
 
 gengtype.o build/gengtype.o : gengtype.c $(SYSTEM_H) gengtype.h 	\
-  rtl.def insn-notes.def errors.h double-int.h version.h $(HASHTAB_H) \
-  $(OBSTACK_H) $(XREGEX_H)
+  rtl.def insn-notes.def errors.h double-int.h wide-int.h version.h     \
+  $(HASHTAB_H) $(OBSTACK_H) $(XREGEX_H)
 gengtype.o: $(CONFIG_H)
 CFLAGS-gengtype.o += -DGENERATOR_FILE
 build/gengtype.o: $(BCONFIG_H)
Index: gcc/sched-vis.c
===================================================================
--- gcc/sched-vis.c	(revision 191978)
+++ gcc/sched-vis.c	(working copy)
@@ -444,14 +444,31 @@ print_value (char *buf, const_rtx x, int
 	       (unsigned HOST_WIDE_INT) INTVAL (x));
       cur = safe_concat (buf, cur, t);
       break;
+
+    case CONST_WIDE_INT:
+      {
+	const char *sep = "<";
+	int i;
+	for (i = CONST_WIDE_INT_NUNITS (x) - 1; i >= 0; i--)
+	  {
+	    cur = safe_concat (buf, cur, sep);
+	    sep = ",";
+	    sprintf (t, HOST_WIDE_INT_PRINT_HEX,
+		     (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, i));
+	    cur = safe_concat (buf, cur, t);
+	  }
+	cur = safe_concat (buf, cur, ">");
+      }
+      break;
+
     case CONST_DOUBLE:
-      if (FLOAT_MODE_P (GET_MODE (x)))
-	real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1);
-      else
+     if (TARGET_SUPPORTS_WIDE_INT == 0 && !FLOAT_MODE_P (GET_MODE (x)))
 	sprintf (t,
 		 "<" HOST_WIDE_INT_PRINT_HEX "," HOST_WIDE_INT_PRINT_HEX ">",
 		 (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x),
 		 (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x));
+      else
+	real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1);
       cur = safe_concat (buf, cur, t);
       break;
     case CONST_FIXED:
Index: gcc/gengtype.c
===================================================================
--- gcc/gengtype.c	(revision 191978)
+++ gcc/gengtype.c	(working copy)
@@ -5440,6 +5440,7 @@ main (int argc, char **argv)
       POS_HERE (do_scalar_typedef ("REAL_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("FIXED_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("double_int", &pos));
+      POS_HERE (do_scalar_typedef ("wide_int", &pos));
       POS_HERE (do_scalar_typedef ("uint64_t", &pos));
       POS_HERE (do_scalar_typedef ("uint8", &pos));
       POS_HERE (do_scalar_typedef ("uintptr_t", &pos));
Index: gcc/alias.c
===================================================================
--- gcc/alias.c	(revision 191978)
+++ gcc/alias.c	(working copy)
@@ -1490,9 +1490,9 @@ rtx_equal_for_memref_p (const_rtx x, con
 
     case VALUE:
     CASE_CONST_UNIQUE:
-      /* There's no need to compare the contents of CONST_DOUBLEs or
-	 CONST_INTs because pointer equality is a good enough
-	 comparison for these nodes.  */
+      /* There's no need to compare the contents of CONST_DOUBLEs,
+	 CONST_INTs or CONST_WIDE_INTs because pointer equality is a
+	 good enough comparison for these nodes.  */
       return 0;
 
     default:
Index: gcc/sel-sched-ir.c
===================================================================
--- gcc/sel-sched-ir.c	(revision 191978)
+++ gcc/sel-sched-ir.c	(working copy)
@@ -1137,10 +1137,10 @@ lhs_and_rhs_separable_p (rtx lhs, rtx rh
   if (lhs == NULL || rhs == NULL)
     return false;
 
-  /* Do not schedule CONST, CONST_INT and CONST_DOUBLE etc as rhs: no point
-     to use reg, if const can be used.  Moreover, scheduling const as rhs may
-     lead to mode mismatch cause consts don't have modes but they could be
-     merged from branches where the same const used in different modes.  */
+  /* Do not schedule constants as rhs: no point to use reg, if const
+     can be used.  Moreover, scheduling const as rhs may lead to mode
+     mismatch cause consts don't have modes but they could be merged
+     from branches where the same const used in different modes.  */
   if (CONSTANT_P (rhs))
     return false;
 
Index: gcc/genemit.c
===================================================================
--- gcc/genemit.c	(revision 191978)
+++ gcc/genemit.c	(working copy)
@@ -205,6 +205,7 @@ gen_exp (rtx x, enum rtx_code subroutine
 
     case CONST_DOUBLE:
     case CONST_FIXED:
+    case CONST_WIDE_INT:
       /* These shouldn't be written in MD files.  Instead, the appropriate
 	 routines in varasm.c should be called.  */
       gcc_unreachable ();
Index: gcc/defaults.h
===================================================================
--- gcc/defaults.h	(revision 191978)
+++ gcc/defaults.h	(working copy)
@@ -1402,6 +1402,14 @@ see the files COPYING3 and COPYING.RUNTI
 #define SWITCHABLE_TARGET 0
 #endif
 
+/* If the target supports integers that are wider than two
+   HOST_WIDE_INTs on the host compiler, then the target should define
+   TARGET_SUPPORTS_WIDE_INT and make the appropriate fixups.
+   Otherwise the compiler really is not robust.  */
+#ifndef TARGET_SUPPORTS_WIDE_INT
+#define TARGET_SUPPORTS_WIDE_INT 0
+#endif
+
 #endif /* GCC_INSN_FLAGS_H  */
 
 #endif  /* ! GCC_DEFAULTS_H */
Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c	(revision 191978)
+++ gcc/builtins.c	(working copy)
@@ -671,20 +671,25 @@ c_getstr (tree src)
   return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
 }
 
-/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
-   GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
+/* Return a CONST_INT, CONST_WIDE_INT, or CONST_DOUBLE corresponding
+   to target reading GET_MODE_BITSIZE (MODE) bits from string constant
+   STR.  */
 
 static rtx
 c_readstr (const char *str, enum machine_mode mode)
 {
-  HOST_WIDE_INT c[2];
+  wide_int c;
   HOST_WIDE_INT ch;
   unsigned int i, j;
+  c.set_mode (mode);
+  c.set_len ((GET_MODE_PRECISION (mode) + HOST_BITS_PER_WIDE_INT - 1)
+	     / HOST_BITS_PER_WIDE_INT);
+
+  for (i = 0; i < c.get_len (); i++)
+    c.elt_ref(i) = 0;
 
   gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
 
-  c[0] = 0;
-  c[1] = 0;
   ch = 1;
   for (i = 0; i < GET_MODE_SIZE (mode); i++)
     {
@@ -695,13 +700,14 @@ c_readstr (const char *str, enum machine
 	  && GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
 	j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
       j *= BITS_PER_UNIT;
-      gcc_assert (j < HOST_BITS_PER_DOUBLE_INT);
 
       if (ch)
 	ch = (unsigned char) str[i];
-      c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
+      c.elt_ref (j / HOST_BITS_PER_WIDE_INT) |= ch << (j % HOST_BITS_PER_WIDE_INT);
     }
-  return immed_double_const (c[0], c[1], mode);
+  
+  c.canonize ();
+  return immed_wide_int_const (c);
 }
 
 /* Cast a target constant CST to target CHAR and if that value fits into
@@ -4990,12 +4996,13 @@ expand_builtin_signbit (tree exp, rtx ta
 
   if (bitpos < GET_MODE_BITSIZE (rmode))
     {
-      double_int mask = double_int_zero.set_bit (bitpos);
+      wide_int mask;
+      mask = wide_int::set_bit_in_zero (bitpos, rmode);
 
       if (GET_MODE_SIZE (imode) > GET_MODE_SIZE (rmode))
 	temp = gen_lowpart (rmode, temp);
       temp = expand_binop (rmode, and_optab, temp,
-			   immed_double_int_const (mask, rmode),
+			   immed_wide_int_const (mask),
 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
   else
Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c	(revision 191978)
+++ gcc/simplify-rtx.c	(working copy)
@@ -88,6 +88,22 @@ mode_signbit_p (enum machine_mode mode,
   if (width <= HOST_BITS_PER_WIDE_INT
       && CONST_INT_P (x))
     val = INTVAL (x);
+#if TARGET_SUPPORTS_WIDE_INT
+  else if (CONST_WIDE_INT_P (x))
+    {
+      unsigned int i;
+      unsigned int elts = CONST_WIDE_INT_NUNITS (x);
+      if (elts != (width + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+	return false;
+      for (i = 0; i < elts - 1; i++)
+	if (CONST_WIDE_INT_ELT (x, i) != 0)
+	  return false;
+      val = CONST_WIDE_INT_ELT (x, elts - 1);
+      width %= HOST_BITS_PER_WIDE_INT;
+      if (width == 0)
+	width = HOST_BITS_PER_WIDE_INT;
+    }
+#else
   else if (width <= HOST_BITS_PER_DOUBLE_INT
 	   && CONST_DOUBLE_AS_INT_P (x)
 	   && CONST_DOUBLE_LOW (x) == 0)
@@ -95,8 +111,9 @@ mode_signbit_p (enum machine_mode mode,
       val = CONST_DOUBLE_HIGH (x);
       width -= HOST_BITS_PER_WIDE_INT;
     }
+#endif
   else
-    /* FIXME: We don't yet have a representation for wider modes.  */
+    /* X is not an integer constant.  */
     return false;
 
   if (width < HOST_BITS_PER_WIDE_INT)
@@ -729,8 +746,8 @@ simplify_unary_operation_1 (enum rtx_cod
 	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
 	{
 	  /* (neg (plus A C)) is simplified to (minus -C A).  */
-	  if (CONST_INT_P (XEXP (op, 1))
-	      || CONST_DOUBLE_P (XEXP (op, 1)))
+	  if (CONST_SCALAR_INT_P (XEXP (op, 1))
+	      || CONST_DOUBLE_AS_FLOAT_P (XEXP (op, 1)))
 	    {
 	      temp = simplify_unary_operation (NEG, mode, XEXP (op, 1), mode);
 	      if (temp)
@@ -1270,7 +1287,6 @@ simplify_const_unary_operation (enum rtx
 				rtx op, enum machine_mode op_mode)
 {
   unsigned int width = GET_MODE_PRECISION (mode);
-  unsigned int op_width = GET_MODE_PRECISION (op_mode);
 
   if (code == VEC_DUPLICATE)
     {
@@ -1283,7 +1299,7 @@ simplify_const_unary_operation (enum rtx
 	  gcc_assert (GET_MODE_INNER (mode) == GET_MODE_INNER
 						(GET_MODE (op)));
       }
-      if (CONST_INT_P (op) || CONST_DOUBLE_P (op)
+      if (CONST_SCALAR_INT_P (op) || CONST_DOUBLE_AS_FLOAT_P (op)
 	  || GET_CODE (op) == CONST_VECTOR)
 	{
           int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
@@ -1336,7 +1352,7 @@ simplify_const_unary_operation (enum rtx
      check the wrong mode (input vs. output) for a conversion operation,
      such as FIX.  At some point, this should be simplified.  */
 
-  if (code == FLOAT && (CONST_DOUBLE_AS_INT_P (op) || CONST_INT_P (op)))
+  if (code == FLOAT && CONST_SCALAR_INT_P (op))
     {
       HOST_WIDE_INT hv, lv;
       REAL_VALUE_TYPE d;
@@ -1344,14 +1360,24 @@ simplify_const_unary_operation (enum rtx
       if (CONST_INT_P (op))
 	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
       else
+#if TARGET_SUPPORTS_WIDE_INT
+	{
+	  /* The conversion code to floats really want exactly 2 HWIs.
+	     This needs to be fixed.  For now, if the constant is
+	     really big, just return 0 which is safe.  */
+	  if (CONST_WIDE_INT_NUNITS (op) > 2)
+	    return 0;
+	  lv = CONST_WIDE_INT_ELT (op, 0);
+	  hv = CONST_WIDE_INT_ELT (op, 1);
+	}
+#else
 	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
-
+#endif
       REAL_VALUE_FROM_INT (d, lv, hv, mode);
       d = real_value_truncate (mode, d);
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
-  else if (code == UNSIGNED_FLOAT
-	   && (CONST_DOUBLE_AS_INT_P (op) || CONST_INT_P (op)))
+  else if (code == UNSIGNED_FLOAT && CONST_SCALAR_INT_P (op))
     {
       HOST_WIDE_INT hv, lv;
       REAL_VALUE_TYPE d;
@@ -1359,8 +1385,19 @@ simplify_const_unary_operation (enum rtx
       if (CONST_INT_P (op))
 	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
       else
+#if TARGET_SUPPORTS_WIDE_INT
+	{
+	  /* The conversion code to floats really want exactly 2 HWIs.
+	     This needs to be fixed.  For now, if the constant is
+	     really big, just return 0 which is safe.  */
+	  if (CONST_WIDE_INT_NUNITS (op) > 2)
+	    return 0;
+	  lv = CONST_WIDE_INT_ELT (op, 0);
+	  hv = CONST_WIDE_INT_ELT (op, 1);
+	}
+#else
 	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
-
+#endif
       if (op_mode == VOIDmode
 	  || GET_MODE_PRECISION (op_mode) > HOST_BITS_PER_DOUBLE_INT)
 	/* We should never get a negative number.  */
@@ -1373,302 +1410,82 @@ simplify_const_unary_operation (enum rtx
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
 
-  if (CONST_INT_P (op)
-      && width <= HOST_BITS_PER_WIDE_INT && width > 0)
+  if (CONST_SCALAR_INT_P (op) && width > 0)
     {
-      HOST_WIDE_INT arg0 = INTVAL (op);
-      HOST_WIDE_INT val;
+      wide_int result;
+      enum machine_mode imode = op_mode == VOIDmode ? mode : op_mode;
+      wide_int op0 = wide_int::from_rtx (op, imode);
+
+#if TARGET_SUPPORTS_WIDE_INT == 0
+      /* This assert keeps the simplification from producing a result
+	 that cannot be represented in a CONST_DOUBLE but a lot of
+	 upstream callers expect that this function never fails to
+	 simplify something and so you if you added this to the test
+	 above the code would die later anyway.  If this assert
+	 happens, you just need to make the port support wide int.  */
+      gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT); 
+#endif
 
       switch (code)
 	{
 	case NOT:
-	  val = ~ arg0;
+	  result = ~op0;
 	  break;
 
 	case NEG:
-	  val = - arg0;
+	  result = op0.neg ();
 	  break;
 
 	case ABS:
-	  val = (arg0 >= 0 ? arg0 : - arg0);
+	  result = op0.abs ();
 	  break;
 
 	case FFS:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = ffs_hwi (arg0);
+	  result = op0.ffs ();
 	  break;
 
 	case CLZ:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0 && CLZ_DEFINED_VALUE_AT_ZERO (mode, val))
-	    ;
-	  else
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 1;
+	  result = op0.clz (mode);
 	  break;
 
 	case CLRSB:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0)
-	    val = GET_MODE_PRECISION (mode) - 1;
-	  else if (arg0 >= 0)
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 2;
-	  else if (arg0 < 0)
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (~arg0) - 2;
+	  result = op0.clrsb (mode);
 	  break;
 
 	case CTZ:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0)
-	    {
-	      /* Even if the value at zero is undefined, we have to come
-		 up with some replacement.  Seems good enough.  */
-	      if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, val))
-		val = GET_MODE_PRECISION (mode);
-	    }
-	  else
-	    val = ctz_hwi (arg0);
+	  result = op0.ctz (mode);
 	  break;
 
 	case POPCOUNT:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = 0;
-	  while (arg0)
-	    val++, arg0 &= arg0 - 1;
+	  result = op0.popcount (mode);
 	  break;
 
 	case PARITY:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = 0;
-	  while (arg0)
-	    val++, arg0 &= arg0 - 1;
-	  val &= 1;
+	  result = op0.parity (mode);
 	  break;
 
 	case BSWAP:
-	  {
-	    unsigned int s;
-
-	    val = 0;
-	    for (s = 0; s < width; s += 8)
-	      {
-		unsigned int d = width - s - 8;
-		unsigned HOST_WIDE_INT byte;
-		byte = (arg0 >> s) & 0xff;
-		val |= byte << d;
-	      }
-	  }
+	  result = op0.bswap ();
 	  break;
 
 	case TRUNCATE:
-	  val = arg0;
+	  result = op0.truncate (mode);
 	  break;
 
 	case ZERO_EXTEND:
-	  /* When zero-extending a CONST_INT, we need to know its
-             original mode.  */
-	  gcc_assert (op_mode != VOIDmode);
-	  if (op_width == HOST_BITS_PER_WIDE_INT)
-	    {
-	      /* If we were really extending the mode,
-		 we would have to distinguish between zero-extension
-		 and sign-extension.  */
-	      gcc_assert (width == op_width);
-	      val = arg0;
-	    }
-	  else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
-	    val = arg0 & GET_MODE_MASK (op_mode);
-	  else
-	    return 0;
+	  result = op0.zext (mode);
 	  break;
 
 	case SIGN_EXTEND:
-	  if (op_mode == VOIDmode)
-	    op_mode = mode;
-	  op_width = GET_MODE_PRECISION (op_mode);
-	  if (op_width == HOST_BITS_PER_WIDE_INT)
-	    {
-	      /* If we were really extending the mode,
-		 we would have to distinguish between zero-extension
-		 and sign-extension.  */
-	      gcc_assert (width == op_width);
-	      val = arg0;
-	    }
-	  else if (op_width < HOST_BITS_PER_WIDE_INT)
-	    {
-	      val = arg0 & GET_MODE_MASK (op_mode);
-	      if (val_signbit_known_set_p (op_mode, val))
-		val |= ~GET_MODE_MASK (op_mode);
-	    }
-	  else
-	    return 0;
+	  result = op0.sext (mode);
 	  break;
 
 	case SQRT:
-	case FLOAT_EXTEND:
-	case FLOAT_TRUNCATE:
-	case SS_TRUNCATE:
-	case US_TRUNCATE:
-	case SS_NEG:
-	case US_NEG:
-	case SS_ABS:
-	  return 0;
-
-	default:
-	  gcc_unreachable ();
-	}
-
-      return gen_int_mode (val, mode);
-    }
-
-  /* We can do some operations on integer CONST_DOUBLEs.  Also allow
-     for a DImode operation on a CONST_INT.  */
-  else if (width <= HOST_BITS_PER_DOUBLE_INT
-	   && (CONST_DOUBLE_AS_INT_P (op) || CONST_INT_P (op)))
-    {
-      double_int first, value;
-
-      if (CONST_DOUBLE_AS_INT_P (op))
-	first = double_int::from_pair (CONST_DOUBLE_HIGH (op),
-				       CONST_DOUBLE_LOW (op));
-      else
-	first = double_int::from_shwi (INTVAL (op));
-
-      switch (code)
-	{
-	case NOT:
-	  value = ~first;
-	  break;
-
-	case NEG:
-	  value = -first;
-	  break;
-
-	case ABS:
-	  if (first.is_negative ())
-	    value = -first;
-	  else
-	    value = first;
-	  break;
-
-	case FFS:
-	  value.high = 0;
-	  if (first.low != 0)
-	    value.low = ffs_hwi (first.low);
-	  else if (first.high != 0)
-	    value.low = HOST_BITS_PER_WIDE_INT + ffs_hwi (first.high);
-	  else
-	    value.low = 0;
-	  break;
-
-	case CLZ:
-	  value.high = 0;
-	  if (first.high != 0)
-	    value.low = GET_MODE_PRECISION (mode) - floor_log2 (first.high) - 1
-	              - HOST_BITS_PER_WIDE_INT;
-	  else if (first.low != 0)
-	    value.low = GET_MODE_PRECISION (mode) - floor_log2 (first.low) - 1;
-	  else if (! CLZ_DEFINED_VALUE_AT_ZERO (mode, value.low))
-	    value.low = GET_MODE_PRECISION (mode);
-	  break;
-
-	case CTZ:
-	  value.high = 0;
-	  if (first.low != 0)
-	    value.low = ctz_hwi (first.low);
-	  else if (first.high != 0)
-	    value.low = HOST_BITS_PER_WIDE_INT + ctz_hwi (first.high);
-	  else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, value.low))
-	    value.low = GET_MODE_PRECISION (mode);
-	  break;
-
-	case POPCOUNT:
-	  value = double_int_zero;
-	  while (first.low)
-	    {
-	      value.low++;
-	      first.low &= first.low - 1;
-	    }
-	  while (first.high)
-	    {
-	      value.low++;
-	      first.high &= first.high - 1;
-	    }
-	  break;
-
-	case PARITY:
-	  value = double_int_zero;
-	  while (first.low)
-	    {
-	      value.low++;
-	      first.low &= first.low - 1;
-	    }
-	  while (first.high)
-	    {
-	      value.low++;
-	      first.high &= first.high - 1;
-	    }
-	  value.low &= 1;
-	  break;
-
-	case BSWAP:
-	  {
-	    unsigned int s;
-
-	    value = double_int_zero;
-	    for (s = 0; s < width; s += 8)
-	      {
-		unsigned int d = width - s - 8;
-		unsigned HOST_WIDE_INT byte;
-
-		if (s < HOST_BITS_PER_WIDE_INT)
-		  byte = (first.low >> s) & 0xff;
-		else
-		  byte = (first.high >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff;
-
-		if (d < HOST_BITS_PER_WIDE_INT)
-		  value.low |= byte << d;
-		else
-		  value.high |= byte << (d - HOST_BITS_PER_WIDE_INT);
-	      }
-	  }
-	  break;
-
-	case TRUNCATE:
-	  /* This is just a change-of-mode, so do nothing.  */
-	  value = first;
-	  break;
-
-	case ZERO_EXTEND:
-	  gcc_assert (op_mode != VOIDmode);
-
-	  if (op_width > HOST_BITS_PER_WIDE_INT)
-	    return 0;
-
-	  value = double_int::from_uhwi (first.low & GET_MODE_MASK (op_mode));
-	  break;
-
-	case SIGN_EXTEND:
-	  if (op_mode == VOIDmode
-	      || op_width > HOST_BITS_PER_WIDE_INT)
-	    return 0;
-	  else
-	    {
-	      value.low = first.low & GET_MODE_MASK (op_mode);
-	      if (val_signbit_known_set_p (op_mode, value.low))
-		value.low |= ~GET_MODE_MASK (op_mode);
-
-	      value.high = HWI_SIGN_EXTEND (value.low);
-	    }
-	  break;
-
-	case SQRT:
-	  return 0;
-
 	default:
 	  return 0;
 	}
 
-      return immed_double_int_const (value, mode);
+      return immed_wide_int_const (result);
     }
 
   else if (CONST_DOUBLE_AS_FLOAT_P (op) 
@@ -1720,7 +1537,6 @@ simplify_const_unary_operation (enum rtx
 	}
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
-
   else if (CONST_DOUBLE_AS_FLOAT_P (op)
 	   && SCALAR_FLOAT_MODE_P (GET_MODE (op))
 	   && GET_MODE_CLASS (mode) == MODE_INT
@@ -1733,9 +1549,13 @@ simplify_const_unary_operation (enum rtx
 
       /* This was formerly used only for non-IEEE float.
 	 eggert@twinsun.com says it is safe for IEEE also.  */
-      HOST_WIDE_INT xh, xl, th, tl;
+      HOST_WIDE_INT th, tl;
       REAL_VALUE_TYPE x, t;
+      wide_int wc;
       REAL_VALUE_FROM_CONST_DOUBLE (x, op);
+      wc.set_mode (mode);
+      wc.set_len (2);
+
       switch (code)
 	{
 	case FIX:
@@ -1757,8 +1577,8 @@ simplify_const_unary_operation (enum rtx
 	  real_from_integer (&t, VOIDmode, tl, th, 0);
 	  if (REAL_VALUES_LESS (t, x))
 	    {
-	      xh = th;
-	      xl = tl;
+	      wc.elt_ref (1) = th;
+	      wc.elt_ref (0) = tl;
 	      break;
 	    }
 
@@ -1777,11 +1597,11 @@ simplify_const_unary_operation (enum rtx
 	  real_from_integer (&t, VOIDmode, tl, th, 0);
 	  if (REAL_VALUES_LESS (x, t))
 	    {
-	      xh = th;
-	      xl = tl;
+	      wc.elt_ref (1) = th;
+	      wc.elt_ref (0) = tl;
 	      break;
 	    }
-	  REAL_VALUE_TO_INT (&xl, &xh, x);
+	  REAL_VALUE_TO_INT (&wc.elt_ref (0), &wc.elt_ref (1), x);
 	  break;
 
 	case UNSIGNED_FIX:
@@ -1808,18 +1628,19 @@ simplify_const_unary_operation (enum rtx
 	  real_from_integer (&t, VOIDmode, tl, th, 1);
 	  if (REAL_VALUES_LESS (t, x))
 	    {
-	      xh = th;
-	      xl = tl;
+	      wc.elt_ref (1) = th;
+	      wc.elt_ref (0) = tl;
 	      break;
 	    }
 
-	  REAL_VALUE_TO_INT (&xl, &xh, x);
+	  REAL_VALUE_TO_INT (&wc.elt_ref (0), &wc.elt_ref (1), x);
 	  break;
 
 	default:
 	  gcc_unreachable ();
 	}
-      return immed_double_const (xl, xh, mode);
+      wc.canonize ();
+      return immed_wide_int_const (wc);
     }
 
   return NULL_RTX;
@@ -1979,49 +1800,50 @@ simplify_binary_operation_1 (enum rtx_co
 
       if (SCALAR_INT_MODE_P (mode))
 	{
-	  double_int coeff0, coeff1;
+	  wide_int coeff0;
+	  wide_int coeff1;
 	  rtx lhs = op0, rhs = op1;
 
-	  coeff0 = double_int_one;
-	  coeff1 = double_int_one;
+	  coeff0 = wide_int_one (mode);
+	  coeff1 = wide_int_one (mode);
 
 	  if (GET_CODE (lhs) == NEG)
 	    {
-	      coeff0 = double_int_minus_one;
+	      coeff0 = wide_int_minus_one (mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == MULT
 		   && CONST_INT_P (XEXP (lhs, 1)))
 	    {
-	      coeff0 = double_int::from_shwi (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::from_rtx (XEXP (lhs, 1), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == ASHIFT
 		   && CONST_INT_P (XEXP (lhs, 1))
                    && INTVAL (XEXP (lhs, 1)) >= 0
-		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (lhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff0 = double_int_zero.set_bit (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::set_bit_in_zero (INTVAL (XEXP (lhs, 1)), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 
 	  if (GET_CODE (rhs) == NEG)
 	    {
-	      coeff1 = double_int_minus_one;
+	      coeff1 = wide_int_minus_one (mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == MULT
 		   && CONST_INT_P (XEXP (rhs, 1)))
 	    {
-	      coeff1 = double_int::from_shwi (INTVAL (XEXP (rhs, 1)));
+	      coeff1 = wide_int::from_rtx (XEXP (rhs, 1), mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == ASHIFT
 		   && CONST_INT_P (XEXP (rhs, 1))
 		   && INTVAL (XEXP (rhs, 1)) >= 0
-		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (rhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff1 = double_int_zero.set_bit (INTVAL (XEXP (rhs, 1)));
+	      coeff1 = wide_int::set_bit_in_zero (INTVAL (XEXP (rhs, 1)), mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 
@@ -2029,11 +1851,9 @@ simplify_binary_operation_1 (enum rtx_co
 	    {
 	      rtx orig = gen_rtx_PLUS (mode, op0, op1);
 	      rtx coeff;
-	      double_int val;
 	      bool speed = optimize_function_for_speed_p (cfun);
 
-	      val = coeff0 + coeff1;
-	      coeff = immed_double_int_const (val, mode);
+	      coeff = immed_wide_int_const (coeff0 + coeff1);
 
 	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
 	      return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
@@ -2042,10 +1862,9 @@ simplify_binary_operation_1 (enum rtx_co
 	}
 
       /* (plus (xor X C1) C2) is (xor X (C1^C2)) if C2 is signbit.  */
-      if ((CONST_INT_P (op1) || CONST_DOUBLE_AS_INT_P (op1))
+      if (CONST_SCALAR_INT_P (op1)
 	  && GET_CODE (op0) == XOR
-	  && (CONST_INT_P (XEXP (op0, 1))
-	      || CONST_DOUBLE_AS_INT_P (XEXP (op0, 1)))
+	  && CONST_SCALAR_INT_P (XEXP (op0, 1))
 	  && mode_signbit_p (mode, op1))
 	return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
 				    simplify_gen_binary (XOR, mode, op1,
@@ -2156,50 +1975,52 @@ simplify_binary_operation_1 (enum rtx_co
 
       if (SCALAR_INT_MODE_P (mode))
 	{
-	  double_int coeff0, negcoeff1;
+	  wide_int coeff0;
+	  wide_int negcoeff1;
 	  rtx lhs = op0, rhs = op1;
 
-	  coeff0 = double_int_one;
-	  negcoeff1 = double_int_minus_one;
+	  coeff0 = wide_int_one (mode);
+	  negcoeff1 = wide_int_minus_one (mode);
 
 	  if (GET_CODE (lhs) == NEG)
 	    {
-	      coeff0 = double_int_minus_one;
+	      coeff0 = wide_int_minus_one (mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == MULT
-		   && CONST_INT_P (XEXP (lhs, 1)))
+		   && CONST_SCALAR_INT_P (XEXP (lhs, 1)))
 	    {
-	      coeff0 = double_int::from_shwi (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::from_rtx (XEXP (lhs, 1), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == ASHIFT
 		   && CONST_INT_P (XEXP (lhs, 1))
 		   && INTVAL (XEXP (lhs, 1)) >= 0
-		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (lhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff0 = double_int_zero.set_bit (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::set_bit_in_zero (INTVAL (XEXP (lhs, 1)), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 
 	  if (GET_CODE (rhs) == NEG)
 	    {
-	      negcoeff1 = double_int_one;
+	      negcoeff1 = wide_int_one (mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == MULT
 		   && CONST_INT_P (XEXP (rhs, 1)))
 	    {
-	      negcoeff1 = double_int::from_shwi (-INTVAL (XEXP (rhs, 1)));
+	      negcoeff1 = wide_int::from_rtx (XEXP (rhs, 1), mode).neg ();
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == ASHIFT
 		   && CONST_INT_P (XEXP (rhs, 1))
 		   && INTVAL (XEXP (rhs, 1)) >= 0
-		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (rhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      negcoeff1 = double_int_zero.set_bit (INTVAL (XEXP (rhs, 1)));
-	      negcoeff1 = -negcoeff1;
+	      negcoeff1 = wide_int::set_bit_in_zero (INTVAL (XEXP (rhs, 1)),
+						    mode);
+	      negcoeff1 = negcoeff1.neg ();
 	      rhs = XEXP (rhs, 0);
 	    }
 
@@ -2207,11 +2028,9 @@ simplify_binary_operation_1 (enum rtx_co
 	    {
 	      rtx orig = gen_rtx_MINUS (mode, op0, op1);
 	      rtx coeff;
-	      double_int val;
 	      bool speed = optimize_function_for_speed_p (cfun);
 
-	      val = coeff0 + negcoeff1;
-	      coeff = immed_double_int_const (val, mode);
+	      coeff = immed_wide_int_const (coeff0 + negcoeff1);
 
 	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
 	      return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
@@ -2225,7 +2044,7 @@ simplify_binary_operation_1 (enum rtx_co
 
       /* (-x - c) may be simplified as (-c - x).  */
       if (GET_CODE (op0) == NEG
-	  && (CONST_INT_P (op1) || CONST_DOUBLE_P (op1)))
+	  && (CONST_SCALAR_INT_P (op1) || CONST_DOUBLE_AS_FLOAT_P (op1)))
 	{
 	  tem = simplify_unary_operation (NEG, mode, op1, mode);
 	  if (tem)
@@ -2363,8 +2182,21 @@ simplify_binary_operation_1 (enum rtx_co
 	  && trueop1 == CONST1_RTX (mode))
 	return op0;
 
-      /* Convert multiply by constant power of two into shift unless
-	 we are still generating RTL.  This test is a kludge.  */
+      /* Convert multiply by constant power of two into shift.  */
+#if TARGET_SUPPORTS_WIDE_INT
+      if (CONST_SCALAR_INT_P (trueop1))
+	{
+	  val = wide_int::from_rtx (trueop1, mode).exact_log2 ();
+	  if (val > 0)
+	    {
+	      unsigned int bitsize = GET_MODE_BITSIZE (mode);
+	      if (SHIFT_COUNT_TRUNCATED && val >= bitsize)
+		val %= bitsize;
+	      if (val < bitsize)
+		return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
+	    }
+	}
+#else
       if (CONST_INT_P (trueop1)
 	  && (val = exact_log2 (UINTVAL (trueop1))) >= 0
 	  /* If the mode is larger than the host word size, and the
@@ -2383,7 +2215,7 @@ simplify_binary_operation_1 (enum rtx_co
 	      || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT))
 	return simplify_gen_binary (ASHIFT, mode, op0,
 				    GEN_INT (val + HOST_BITS_PER_WIDE_INT));
-
+#endif
       /* x*2 is x+x and x*(-1) is -x */
       if (CONST_DOUBLE_AS_FLOAT_P (trueop1)
 	  && SCALAR_FLOAT_MODE_P (GET_MODE (trueop1))
@@ -2583,14 +2415,13 @@ simplify_binary_operation_1 (enum rtx_co
 	 return CONST0_RTX (mode);
 
       /* Canonicalize XOR of the most significant bit to PLUS.  */
-      if ((CONST_INT_P (op1) || CONST_DOUBLE_AS_INT_P (op1))
+      if (CONST_SCALAR_INT_P (op1)
 	  && mode_signbit_p (mode, op1))
 	return simplify_gen_binary (PLUS, mode, op0, op1);
       /* (xor (plus X C1) C2) is (xor X (C1^C2)) if C1 is signbit.  */
-      if ((CONST_INT_P (op1) || CONST_DOUBLE_AS_INT_P (op1))
+      if (CONST_SCALAR_INT_P (op1)
 	  && GET_CODE (op0) == PLUS
-	  && (CONST_INT_P (XEXP (op0, 1))
-	      || CONST_DOUBLE_AS_INT_P (XEXP (op0, 1)))
+	  && CONST_SCALAR_INT_P (XEXP (op0, 1))
 	  && mode_signbit_p (mode, XEXP (op0, 1)))
 	return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
 				    simplify_gen_binary (XOR, mode, op1,
@@ -3355,9 +3186,11 @@ simplify_binary_operation_1 (enum rtx_co
 	  gcc_assert (GET_MODE_INNER (mode) == op1_mode);
 
 	if ((GET_CODE (trueop0) == CONST_VECTOR
-	     || CONST_INT_P (trueop0) || CONST_DOUBLE_P (trueop0))
+	     || CONST_SCALAR_INT_P (trueop0) 
+	     || CONST_DOUBLE_AS_FLOAT_P (trueop0))
 	    && (GET_CODE (trueop1) == CONST_VECTOR
-		|| CONST_INT_P (trueop1) || CONST_DOUBLE_P (trueop1)))
+		|| CONST_SCALAR_INT_P (trueop1) 
+		|| CONST_DOUBLE_AS_FLOAT_P (trueop1)))
 	  {
 	    int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
 	    unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
@@ -3420,9 +3253,9 @@ rtx
 simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 				 rtx op0, rtx op1)
 {
-  HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
-  HOST_WIDE_INT val;
+#if TARGET_SUPPORTS_WIDE_INT == 0
   unsigned int width = GET_MODE_PRECISION (mode);
+#endif
 
   if (VECTOR_MODE_P (mode)
       && code != VEC_CONCAT
@@ -3454,11 +3287,11 @@ simplify_const_binary_operation (enum rt
 
   if (VECTOR_MODE_P (mode)
       && code == VEC_CONCAT
-      && (CONST_INT_P (op0)
+      && (CONST_SCALAR_INT_P (op0)
 	  || GET_CODE (op0) == CONST_FIXED
-	  || CONST_DOUBLE_P (op0))
-      && (CONST_INT_P (op1)
-	  || CONST_DOUBLE_P (op1)
+	  || CONST_DOUBLE_AS_FLOAT_P (op0))
+      && (CONST_SCALAR_INT_P (op1)
+	  || CONST_DOUBLE_AS_FLOAT_P (op1)
 	  || GET_CODE (op1) == CONST_FIXED))
     {
       unsigned n_elts = GET_MODE_NUNITS (mode);
@@ -3615,299 +3448,128 @@ simplify_const_binary_operation (enum rt
 
   /* We can fold some multi-word operations.  */
   if (GET_MODE_CLASS (mode) == MODE_INT
-      && width == HOST_BITS_PER_DOUBLE_INT
-      && (CONST_DOUBLE_AS_INT_P (op0) || CONST_INT_P (op0))
-      && (CONST_DOUBLE_AS_INT_P (op1) || CONST_INT_P (op1)))
+      && CONST_SCALAR_INT_P (op0)
+      && CONST_SCALAR_INT_P (op1))
     {
-      double_int o0, o1, res, tmp;
-      bool overflow;
-
-      o0 = rtx_to_double_int (op0);
-      o1 = rtx_to_double_int (op1);
-
+      wide_int result;
+      wide_int wop0 = wide_int::from_rtx (op0, mode);
+      wide_int wop1 = wide_int::from_rtx (op1, mode);
+      bool overflow = false;
+
+#if TARGET_SUPPORTS_WIDE_INT == 0
+      /* This assert keeps the simplification from producing a result
+	 that cannot be represented in a CONST_DOUBLE but a lot of
+	 upstream callers expect that this function never fails to
+	 simplify something and so you if you added this to the test
+	 above the code would die later anyway.  If this assert
+	 happens, you just need to make the port support wide int.  */
+      gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT);
+#endif
       switch (code)
 	{
 	case MINUS:
-	  /* A - B == A + (-B).  */
-	  o1 = -o1;
-
-	  /* Fall through....  */
+	  result = wop0 - wop1;
+	  break;
 
 	case PLUS:
-	  res = o0 + o1;
+	  result = wop0 + wop1;
 	  break;
 
 	case MULT:
-	  res = o0 * o1;
+	  result = wop0 * wop1;
 	  break;
 
 	case DIV:
-          res = o0.divmod_with_overflow (o1, false, TRUNC_DIV_EXPR,
-					 &tmp, &overflow);
+	  result = wop0.div_trunc (wop1, wide_int::SIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
-
+	  
 	case MOD:
-          tmp = o0.divmod_with_overflow (o1, false, TRUNC_DIV_EXPR,
-					 &res, &overflow);
+	  result = wop0.mod_trunc (wop1, wide_int::SIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case UDIV:
-          res = o0.divmod_with_overflow (o1, true, TRUNC_DIV_EXPR,
-					 &tmp, &overflow);
+	  result = wop0.div_trunc (wop1, wide_int::UNSIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case UMOD:
-          tmp = o0.divmod_with_overflow (o1, true, TRUNC_DIV_EXPR,
-					 &res, &overflow);
+	  result = wop0.mod_trunc (wop1, wide_int::UNSIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case AND:
-	  res = o0 & o1;
+	  result = wop0 & wop1;
 	  break;
 
 	case IOR:
-	  res = o0 | o1;
+	  result = wop0 | wop1;
 	  break;
 
 	case XOR:
-	  res = o0 ^ o1;
+	  result = wop0 ^ wop1;
 	  break;
 
 	case SMIN:
-	  res = o0.smin (o1);
+	  result = wide_int_smin (wop0, wop1);
 	  break;
 
 	case SMAX:
-	  res = o0.smax (o1);
+	  result = wide_int_smax (wop0, wop1);
 	  break;
 
 	case UMIN:
-	  res = o0.umin (o1);
+	  result = wide_int_umin (wop0, wop1);
 	  break;
 
 	case UMAX:
-	  res = o0.umax (o1);
-	  break;
-
-	case LSHIFTRT:   case ASHIFTRT:
-	case ASHIFT:
-	case ROTATE:     case ROTATERT:
-	  {
-	    unsigned HOST_WIDE_INT cnt;
-
-	    if (SHIFT_COUNT_TRUNCATED)
-	      {
-		o1.high = 0; 
-		o1.low &= GET_MODE_PRECISION (mode) - 1;
-	      }
-
-	    if (!o1.fits_uhwi ()
-	        || o1.to_uhwi () >= GET_MODE_PRECISION (mode))
-	      return 0;
-
-	    cnt = o1.to_uhwi ();
-	    unsigned short prec = GET_MODE_PRECISION (mode);
-
-	    if (code == LSHIFTRT || code == ASHIFTRT)
-	      res = o0.rshift (cnt, prec, code == ASHIFTRT);
-	    else if (code == ASHIFT)
-	      res = o0.alshift (cnt, prec);
-	    else if (code == ROTATE)
-	      res = o0.lrotate (cnt, prec);
-	    else /* code == ROTATERT */
-	      res = o0.rrotate (cnt, prec);
-	  }
-	  break;
-
-	default:
-	  return 0;
-	}
-
-      return immed_double_int_const (res, mode);
-    }
-
-  if (CONST_INT_P (op0) && CONST_INT_P (op1)
-      && width <= HOST_BITS_PER_WIDE_INT && width != 0)
-    {
-      /* Get the integer argument values in two forms:
-         zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S.  */
-
-      arg0 = INTVAL (op0);
-      arg1 = INTVAL (op1);
-
-      if (width < HOST_BITS_PER_WIDE_INT)
-        {
-          arg0 &= GET_MODE_MASK (mode);
-          arg1 &= GET_MODE_MASK (mode);
-
-          arg0s = arg0;
-	  if (val_signbit_known_set_p (mode, arg0s))
-	    arg0s |= ~GET_MODE_MASK (mode);
-
-          arg1s = arg1;
-	  if (val_signbit_known_set_p (mode, arg1s))
-	    arg1s |= ~GET_MODE_MASK (mode);
-	}
-      else
-	{
-	  arg0s = arg0;
-	  arg1s = arg1;
-	}
-
-      /* Compute the value of the arithmetic.  */
-
-      switch (code)
-	{
-	case PLUS:
-	  val = arg0s + arg1s;
-	  break;
-
-	case MINUS:
-	  val = arg0s - arg1s;
-	  break;
-
-	case MULT:
-	  val = arg0s * arg1s;
-	  break;
-
-	case DIV:
-	  if (arg1s == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = arg0s / arg1s;
-	  break;
-
-	case MOD:
-	  if (arg1s == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = arg0s % arg1s;
+	  result = wide_int_umax (wop0, wop1);
 	  break;
 
-	case UDIV:
-	  if (arg1 == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = (unsigned HOST_WIDE_INT) arg0 / arg1;
-	  break;
-
-	case UMOD:
-	  if (arg1 == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = (unsigned HOST_WIDE_INT) arg0 % arg1;
-	  break;
-
-	case AND:
-	  val = arg0 & arg1;
-	  break;
+	case LSHIFTRT:
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	case IOR:
-	  val = arg0 | arg1;
+	  result = wop0.rshiftu (wop1, wide_int::TRUNC);
 	  break;
-
-	case XOR:
-	  val = arg0 ^ arg1;
-	  break;
-
-	case LSHIFTRT:
-	case ASHIFT:
+	  
 	case ASHIFTRT:
-	  /* Truncate the shift if SHIFT_COUNT_TRUNCATED, otherwise make sure
-	     the value is in range.  We can't return any old value for
-	     out-of-range arguments because either the middle-end (via
-	     shift_truncation_mask) or the back-end might be relying on
-	     target-specific knowledge.  Nor can we rely on
-	     shift_truncation_mask, since the shift might not be part of an
-	     ashlM3, lshrM3 or ashrM3 instruction.  */
-	  if (SHIFT_COUNT_TRUNCATED)
-	    arg1 = (unsigned HOST_WIDE_INT) arg1 % width;
-	  else if (arg1 < 0 || arg1 >= GET_MODE_BITSIZE (mode))
-	    return 0;
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	  val = (code == ASHIFT
-		 ? ((unsigned HOST_WIDE_INT) arg0) << arg1
-		 : ((unsigned HOST_WIDE_INT) arg0) >> arg1);
-
-	  /* Sign-extend the result for arithmetic right shifts.  */
-	  if (code == ASHIFTRT && arg0s < 0 && arg1 > 0)
-	    val |= ((unsigned HOST_WIDE_INT) (-1)) << (width - arg1);
+	  result = wop0.rshifts (wop1, wide_int::TRUNC);
 	  break;
+	  
+	case ASHIFT:
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	case ROTATERT:
-	  if (arg1 < 0)
-	    return 0;
-
-	  arg1 %= width;
-	  val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
-		 | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
+	  result = wop0.lshift (wop1, wide_int::TRUNC);
 	  break;
-
+	  
 	case ROTATE:
-	  if (arg1 < 0)
-	    return 0;
-
-	  arg1 %= width;
-	  val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
-		 | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
-	  break;
-
-	case COMPARE:
-	  /* Do nothing here.  */
-	  return 0;
-
-	case SMIN:
-	  val = arg0s <= arg1s ? arg0s : arg1s;
-	  break;
-
-	case UMIN:
-	  val = ((unsigned HOST_WIDE_INT) arg0
-		 <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
-	  break;
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	case SMAX:
-	  val = arg0s > arg1s ? arg0s : arg1s;
+	  result = wop0.lrotate (wop1);
 	  break;
+	  
+	case ROTATERT:
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	case UMAX:
-	  val = ((unsigned HOST_WIDE_INT) arg0
-		 > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
+	  result = wop0.rrotate (wop1);
 	  break;
 
-	case SS_PLUS:
-	case US_PLUS:
-	case SS_MINUS:
-	case US_MINUS:
-	case SS_MULT:
-	case US_MULT:
-	case SS_DIV:
-	case US_DIV:
-	case SS_ASHIFT:
-	case US_ASHIFT:
-	  /* ??? There are simplifications that can be done.  */
-	  return 0;
-
 	default:
-	  gcc_unreachable ();
+	  return NULL_RTX;
 	}
-
-      return gen_int_mode (val, mode);
+      return immed_wide_int_const (result);
     }
 
   return NULL_RTX;
@@ -4482,9 +4144,8 @@ simplify_relational_operation_1 (enum rt
   /* (eq/ne (xor x C1) C2) simplifies to (eq/ne x (C1^C2)).  */
   if ((code == EQ || code == NE)
       && op0code == XOR
-      && (CONST_INT_P (op1) || CONST_DOUBLE_AS_INT_P (op1))
-      && (CONST_INT_P (XEXP (op0, 1))
-	  || CONST_DOUBLE_AS_INT_P (XEXP (op0, 1))))
+      && CONST_SCALAR_INT_P (op1)
+      && CONST_SCALAR_INT_P (XEXP (op0, 1)))
     return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 0),
 				    simplify_gen_binary (XOR, cmp_mode,
 							 XEXP (op0, 1), op1));
@@ -4574,10 +4235,11 @@ comparison_result (enum rtx_code code, i
     }
 }
 
-/* Check if the given comparison (done in the given MODE) is actually a
-   tautology or a contradiction.
-   If no simplification is possible, this function returns zero.
-   Otherwise, it returns either const_true_rtx or const0_rtx.  */
+/* Check if the given comparison (done in the given MODE) is actually
+   a tautology or a contradiction.  If the mode is VOID_mode, the
+   comparison is done in "infinite precision".  If no simplification
+   is possible, this function returns zero.  Otherwise, it returns
+   either const_true_rtx or const0_rtx.  */
 
 rtx
 simplify_const_relational_operation (enum rtx_code code,
@@ -4701,59 +4363,25 @@ simplify_const_relational_operation (enu
 
   /* Otherwise, see if the operands are both integers.  */
   if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
-       && (CONST_DOUBLE_AS_INT_P (trueop0) || CONST_INT_P (trueop0))
-       && (CONST_DOUBLE_AS_INT_P (trueop1) || CONST_INT_P (trueop1)))
+      && CONST_SCALAR_INT_P (trueop0) && CONST_SCALAR_INT_P (trueop1))
     {
-      int width = GET_MODE_PRECISION (mode);
-      HOST_WIDE_INT l0s, h0s, l1s, h1s;
-      unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
-
-      /* Get the two words comprising each integer constant.  */
-      if (CONST_DOUBLE_AS_INT_P (trueop0))
-	{
-	  l0u = l0s = CONST_DOUBLE_LOW (trueop0);
-	  h0u = h0s = CONST_DOUBLE_HIGH (trueop0);
-	}
-      else
-	{
-	  l0u = l0s = INTVAL (trueop0);
-	  h0u = h0s = HWI_SIGN_EXTEND (l0s);
-	}
-
-      if (CONST_DOUBLE_AS_INT_P (trueop1))
-	{
-	  l1u = l1s = CONST_DOUBLE_LOW (trueop1);
-	  h1u = h1s = CONST_DOUBLE_HIGH (trueop1);
-	}
-      else
-	{
-	  l1u = l1s = INTVAL (trueop1);
-	  h1u = h1s = HWI_SIGN_EXTEND (l1s);
-	}
-
-      /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
-	 we have to sign or zero-extend the values.  */
-      if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
-	{
-	  l0u &= GET_MODE_MASK (mode);
-	  l1u &= GET_MODE_MASK (mode);
-
-	  if (val_signbit_known_set_p (mode, l0s))
-	    l0s |= ~GET_MODE_MASK (mode);
-
-	  if (val_signbit_known_set_p (mode, l1s))
-	    l1s |= ~GET_MODE_MASK (mode);
-	}
-      if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
-	h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
-
-      if (h0u == h1u && l0u == l1u)
+      enum machine_mode cmode = mode;
+      wide_int wo0;
+      wide_int wo1;
+
+      /* It would be nice if we really had a mode here.  However, the
+	 largest int representable on the target is as good as
+	 infinite.  */
+      if (mode == VOIDmode)
+	cmode = MAX_MODE_INT;
+      wo0 = wide_int::from_rtx (trueop0, cmode);
+      wo1 = wide_int::from_rtx (trueop1, cmode);
+      if (wo0 == wo1)
 	return comparison_result (code, CMP_EQ);
       else
 	{
-	  int cr;
-	  cr = (h0s < h1s || (h0s == h1s && l0u < l1u)) ? CMP_LT : CMP_GT;
-	  cr |= (h0u < h1u || (h0u == h1u && l0u < l1u)) ? CMP_LTU : CMP_GTU;
+	  int cr = wo0.lts_p (wo1) ? CMP_LT : CMP_GT;
+	  cr |= wo0.ltu_p (wo1) ? CMP_LTU : CMP_GTU;
 	  return comparison_result (code, cr);
 	}
     }
@@ -5168,9 +4796,9 @@ simplify_ternary_operation (enum rtx_cod
   return 0;
 }
 
-/* Evaluate a SUBREG of a CONST_INT or CONST_DOUBLE or CONST_FIXED
-   or CONST_VECTOR,
-   returning another CONST_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
+/* Evaluate a SUBREG of a CONST_INT or CONST_WIDE_INT or CONST_DOUBLE
+   or CONST_FIXED or CONST_VECTOR, returning another CONST_INT or
+   CONST_WIDE_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
 
    Works by unpacking OP into a collection of 8-bit values
    represented as a little-endian array of 'unsigned char', selecting by BYTE,
@@ -5180,13 +4808,11 @@ static rtx
 simplify_immed_subreg (enum machine_mode outermode, rtx op,
 		       enum machine_mode innermode, unsigned int byte)
 {
-  /* We support up to 512-bit values (for V8DFmode).  */
   enum {
-    max_bitsize = 512,
     value_bit = 8,
     value_mask = (1 << value_bit) - 1
   };
-  unsigned char value[max_bitsize / value_bit];
+  unsigned char value [MAX_BITSIZE_MODE_ANY_MODE/value_bit];
   int value_start;
   int i;
   int elem;
@@ -5198,6 +4824,7 @@ simplify_immed_subreg (enum machine_mode
   rtvec result_v = NULL;
   enum mode_class outer_class;
   enum machine_mode outer_submode;
+  int max_bitsize;
 
   /* Some ports misuse CCmode.  */
   if (GET_MODE_CLASS (outermode) == MODE_CC && CONST_INT_P (op))
@@ -5207,6 +4834,9 @@ simplify_immed_subreg (enum machine_mode
   if (COMPLEX_MODE_P (outermode))
     return NULL_RTX;
 
+  /* We support any size mode.  */
+  max_bitsize = MAX (GET_MODE_BITSIZE (outermode), GET_MODE_BITSIZE (innermode));
+
   /* Unpack the value.  */
 
   if (GET_CODE (op) == CONST_VECTOR)
@@ -5256,8 +4886,20 @@ simplify_immed_subreg (enum machine_mode
 	    *vp++ = INTVAL (el) < 0 ? -1 : 0;
 	  break;
 
+	case CONST_WIDE_INT:
+	  {
+	    wide_int val = wide_int::from_rtx (el, innermode);
+	    unsigned char extend = val.sign_mask ();
+
+	    for (i = 0; i < elem_bitsize; i += value_bit) 
+	      *vp++ = val.extract_to_hwi (i, value_bit);
+	    for (; i < elem_bitsize; i += value_bit)
+	      *vp++ = extend;
+	  }
+	  break;
+
 	case CONST_DOUBLE:
-	  if (GET_MODE (el) == VOIDmode)
+	  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (el) == VOIDmode)
 	    {
 	      unsigned char extend = 0;
 	      /* If this triggers, someone should have generated a
@@ -5280,7 +4922,8 @@ simplify_immed_subreg (enum machine_mode
 	    }
 	  else
 	    {
-	      long tmp[max_bitsize / 32];
+	      /* This is big enough for anything on the platform.  */
+	      long tmp[MAX_BITSIZE_MODE_ANY_MODE / 32];
 	      int bitsize = GET_MODE_BITSIZE (GET_MODE (el));
 
 	      gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (el)));
@@ -5400,24 +5043,27 @@ simplify_immed_subreg (enum machine_mode
 	case MODE_INT:
 	case MODE_PARTIAL_INT:
 	  {
-	    unsigned HOST_WIDE_INT hi = 0, lo = 0;
-
-	    for (i = 0;
-		 i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
-		 i += value_bit)
-	      lo |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
-	    for (; i < elem_bitsize; i += value_bit)
-	      hi |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask)
-		     << (i - HOST_BITS_PER_WIDE_INT);
+	    int u;
+	    int base = 0;
+	    int units 
+	      = (GET_MODE_BITSIZE (outer_submode) + HOST_BITS_PER_WIDE_INT - 1) 
+	      / HOST_BITS_PER_WIDE_INT;
+	    wide_int r;
+	    for (u = 0; u < units; u++) 
+	      {
+		unsigned HOST_WIDE_INT buf = 0;
+		for (i = 0; 
+		     i < HOST_BITS_PER_WIDE_INT && base + i < elem_bitsize; 
+		     i += value_bit)
+		  buf |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
 
-	    /* immed_double_const doesn't call trunc_int_for_mode.  I don't
-	       know why.  */
-	    if (elem_bitsize <= HOST_BITS_PER_WIDE_INT)
-	      elems[elem] = gen_int_mode (lo, outer_submode);
-	    else if (elem_bitsize <= HOST_BITS_PER_DOUBLE_INT)
-	      elems[elem] = immed_double_const (lo, hi, outer_submode);
-	    else
-	      return NULL_RTX;
+		r.elt_ref (u) = buf;
+		base += HOST_BITS_PER_WIDE_INT;
+	      }
+	    r.set_len (units);
+	    r.set_mode (outer_submode);
+	    r.canonize ();
+	    elems[elem] = immed_wide_int_const (r);
 	  }
 	  break;
 
@@ -5425,7 +5071,7 @@ simplify_immed_subreg (enum machine_mode
 	case MODE_DECIMAL_FLOAT:
 	  {
 	    REAL_VALUE_TYPE r;
-	    long tmp[max_bitsize / 32];
+	    long tmp[MAX_BITSIZE_MODE_ANY_INT / 32];
 
 	    /* real_from_target wants its input in words affected by
 	       FLOAT_WORDS_BIG_ENDIAN.  However, we ignore this,
@@ -5501,8 +5147,8 @@ simplify_subreg (enum machine_mode outer
   if (outermode == innermode && !byte)
     return op;
 
-  if (CONST_INT_P (op)
-      || CONST_DOUBLE_P (op)
+  if (CONST_SCALAR_INT_P (op)
+      || CONST_DOUBLE_AS_FLOAT_P (op)
       || GET_CODE (op) == CONST_FIXED
       || GET_CODE (op) == CONST_VECTOR)
     return simplify_immed_subreg (outermode, op, innermode, byte);
Index: gcc/gengenrtl.c
===================================================================
--- gcc/gengenrtl.c	(revision 191978)
+++ gcc/gengenrtl.c	(working copy)
@@ -143,6 +143,7 @@ static int
 excluded_rtx (int idx)
 {
   return ((strcmp (defs[idx].enumname, "CONST_DOUBLE") == 0)
+	  || (strcmp (defs[idx].enumname, "CONST_WIDE_INT") == 0)
 	  || (strcmp (defs[idx].enumname, "CONST_FIXED") == 0));
 }
 
Index: gcc/expmed.c
===================================================================
--- gcc/expmed.c	(revision 191978)
+++ gcc/expmed.c	(working copy)
@@ -60,7 +60,6 @@ static rtx extract_fixed_bit_field (enum
 				    unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT, rtx, int, bool);
-static rtx mask_rtx (enum machine_mode, int, int, int);
 static rtx lshift_value (enum machine_mode, rtx, int, int);
 static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT, int);
@@ -68,6 +67,19 @@ static void do_cmp_and_jump (rtx, rtx, e
 static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 
+/* Return a constant integer (CONST_INT or CONST_WIDE_INT) mask value
+   of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
+   complement of that if COMPLEMENT.  The mask is truncated if
+   necessary to the width of mode MODE.  The mask is zero-extended if
+   BITSIZE+BITPOS is too small for MODE.  */
+
+static inline rtx 
+mask_rtx (enum machine_mode mode, int bitpos, int bitsize, bool complement)
+{
+  return immed_wide_int_const 
+    (wide_int::shifted_mask (bitpos, bitsize, complement, mode));
+}
+
 /* Test whether a value is zero of a power of two.  */
 #define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
 
@@ -1961,39 +1973,16 @@ extract_fixed_bit_field (enum machine_mo
   return expand_shift (RSHIFT_EXPR, mode, op0,
 		       GET_MODE_BITSIZE (mode) - bitsize, target, 0);
 }
-\f
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) mask value
-   of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
-   complement of that if COMPLEMENT.  The mask is truncated if
-   necessary to the width of mode MODE.  The mask is zero-extended if
-   BITSIZE+BITPOS is too small for MODE.  */
-
-static rtx
-mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
-{
-  double_int mask;
-
-  mask = double_int::mask (bitsize);
-  mask = mask.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
-  if (complement)
-    mask = ~mask;
-
-  return immed_double_int_const (mask, mode);
-}
-
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
-   VALUE truncated to BITSIZE bits and then shifted left BITPOS bits.  */
+/* Return a constant integer (CONST_INT or CONST_WIDE_INT) rtx with the value
+   VALUE truncated to BITSIZE bits and then shifted left BITPOS bits.   */
 
 static rtx
 lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
 {
-  double_int val;
-  
-  val = double_int::from_uhwi (INTVAL (value)).zext (bitsize);
-  val = val.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
-  return immed_double_int_const (val, mode);
+  return 
+    immed_wide_int_const (wide_int::from_rtx (value, mode)
+			  .zext (bitsize)
+			  .lshift (bitpos, wide_int::NONE));
 }
 \f
 /* Extract a bit field that is split across two words
@@ -3199,34 +3188,41 @@ expand_mult (enum machine_mode mode, rtx
 	 only if the constant value exactly fits in an `unsigned int' without
 	 any truncation.  This means that multiplying by negative values does
 	 not work; results are off by 2^32 on a 32 bit machine.  */
-
       if (CONST_INT_P (scalar_op1))
 	{
 	  coeff = INTVAL (scalar_op1);
 	  is_neg = coeff < 0;
 	}
+#if TARGET_SUPPORTS_WIDE_INT
+      else if (CONST_WIDE_INT_P (scalar_op1))
+#else
       else if (CONST_DOUBLE_AS_INT_P (scalar_op1))
+#endif
 	{
-	  /* If we are multiplying in DImode, it may still be a win
-	     to try to work with shifts and adds.  */
-	  if (CONST_DOUBLE_HIGH (scalar_op1) == 0
-	      && CONST_DOUBLE_LOW (scalar_op1) > 0)
+	  int p = GET_MODE_PRECISION (mode);
+	  wide_int val = wide_int::from_rtx (scalar_op1, mode);
+	  int shift = val.exact_log2 (); 
+	  /* Perfect power of 2.  */
+	  is_neg = false;
+	  if (shift > 0)
 	    {
-	      coeff = CONST_DOUBLE_LOW (scalar_op1);
-	      is_neg = false;
+	      /* Do the shift count trucation against the bitsize, not
+		 the precision.  See the comment above
+		 wide-int.c:trunc_shift for details.  */
+	      if (SHIFT_COUNT_TRUNCATED)
+		shift &= GET_MODE_BITSIZE (mode) - 1;
+	      /* We could consider adding just a move of 0 to target
+		 if the shift >= p  */
+	      if (shift < p)
+		return expand_shift (LSHIFT_EXPR, mode, op0, 
+				     shift, target, unsignedp);
+	      /* Any positive number that fits in a word.  */
+	      coeff = CONST_WIDE_INT_ELT (scalar_op1, 0);
 	    }
-	  else if (CONST_DOUBLE_LOW (scalar_op1) == 0)
+	  else if (val.sign_mask () == 0)
 	    {
-	      coeff = CONST_DOUBLE_HIGH (scalar_op1);
-	      if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
-		{
-		  int shift = floor_log2 (coeff) + HOST_BITS_PER_WIDE_INT;
-		  if (shift < HOST_BITS_PER_DOUBLE_INT - 1
-		      || mode_bitsize <= HOST_BITS_PER_DOUBLE_INT)
-		    return expand_shift (LSHIFT_EXPR, mode, op0,
-					 shift, target, unsignedp);
-		}
-	      goto skip_synth;
+	      /* Any positive number that fits in a word.  */
+	      coeff = CONST_WIDE_INT_ELT (scalar_op1, 0);
 	    }
 	  else
 	    goto skip_synth;
@@ -3716,9 +3712,10 @@ expmed_mult_highpart (enum machine_mode
 static rtx
 expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 {
-  unsigned HOST_WIDE_INT masklow, maskhigh;
   rtx result, temp, shift, label;
   int logd;
+  wide_int mask;
+  int prec = GET_MODE_PRECISION (mode);
 
   logd = floor_log2 (d);
   result = gen_reg_rtx (mode);
@@ -3731,8 +3728,8 @@ expand_smod_pow2 (enum machine_mode mode
 				      mode, 0, -1);
       if (signmask)
 	{
+	  HOST_WIDE_INT masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
 	  signmask = force_reg (mode, signmask);
-	  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
 	  shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
 
 	  /* Use the rtx_cost of a LSHIFTRT instruction to determine
@@ -3777,19 +3774,11 @@ expand_smod_pow2 (enum machine_mode mode
      modulus.  By including the signbit in the operation, many targets
      can avoid an explicit compare operation in the following comparison
      against zero.  */
-
-  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
-  if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
-    {
-      masklow |= (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1);
-      maskhigh = -1;
-    }
-  else
-    maskhigh = (HOST_WIDE_INT) -1
-		 << (GET_MODE_BITSIZE (mode) - HOST_BITS_PER_WIDE_INT - 1);
+  mask = wide_int::mask (logd, false, mode);
+  mask = mask.set_bit (prec - 1);
 
   temp = expand_binop (mode, and_optab, op0,
-		       immed_double_const (masklow, maskhigh, mode),
+		       immed_wide_int_const (mask),
 		       result, 1, OPTAB_LIB_WIDEN);
   if (temp != result)
     emit_move_insn (result, temp);
@@ -3799,10 +3788,10 @@ expand_smod_pow2 (enum machine_mode mode
 
   temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
 		       0, OPTAB_LIB_WIDEN);
-  masklow = (HOST_WIDE_INT) -1 << logd;
-  maskhigh = -1;
+
+  mask = wide_int::mask (logd, true, mode); 
   temp = expand_binop (mode, ior_optab, temp,
-		       immed_double_const (masklow, maskhigh, mode),
+		       immed_wide_int_const (mask),
 		       result, 1, OPTAB_LIB_WIDEN);
   temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
 		       0, OPTAB_LIB_WIDEN);
@@ -5056,8 +5045,12 @@ make_tree (tree type, rtx x)
 	return t;
       }
 
+    case CONST_WIDE_INT:
+      t = wide_int_to_tree (type, wide_int::from_rtx (x, TYPE_MODE (type)));
+      return t;
+
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	t = build_int_cst_wide (type,
 				CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
       else
Index: gcc/cselib.c
===================================================================
--- gcc/cselib.c	(revision 191978)
+++ gcc/cselib.c	(working copy)
@@ -534,17 +534,15 @@ entry_and_rtx_equal_p (const void *entry
   rtx x = CONST_CAST_RTX ((const_rtx)x_arg);
   enum machine_mode mode = GET_MODE (x);
 
-  gcc_assert (!CONST_INT_P (x) && GET_CODE (x) != CONST_FIXED
-	      && (mode != VOIDmode || GET_CODE (x) != CONST_DOUBLE));
+  gcc_assert (!CONST_SCALAR_INT_P (x) && GET_CODE (x) != CONST_FIXED);
 
   if (mode != GET_MODE (v->val_rtx))
     return 0;
 
   /* Unwrap X if necessary.  */
   if (GET_CODE (x) == CONST
-      && (CONST_INT_P (XEXP (x, 0))
-	  || GET_CODE (XEXP (x, 0)) == CONST_FIXED
-	  || GET_CODE (XEXP (x, 0)) == CONST_DOUBLE))
+      && (CONST_SCALAR_INT_P (XEXP (x, 0))
+	  || GET_CODE (XEXP (x, 0)) == CONST_FIXED))
     x = XEXP (x, 0);
 
   /* We don't guarantee that distinct rtx's have different hash values,
@@ -911,6 +913,20 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, en
     case DEBUG_EXPR:
       return 0;
 
+    case CONST_WIDE_INT:
+      {
+	int i;
+	/* It would have been nice to have had a mode.  */
+	if (CONST_WIDE_INT_NUNITS (x) != CONST_WIDE_INT_NUNITS (y))
+	  return 0;
+
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  if (CONST_WIDE_INT_ELT (x, i) != CONST_WIDE_INT_ELT (y, i))
+	    return 0;
+
+	return 1;
+      }
+
     case DEBUG_IMPLICIT_PTR:
       return DEBUG_IMPLICIT_PTR_DECL (x)
 	     == DEBUG_IMPLICIT_PTR_DECL (y);
@@ -1009,9 +1025,7 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, en
 static rtx
 wrap_constant (enum machine_mode mode, rtx x)
 {
-  if (!CONST_INT_P (x) 
-      && GET_CODE (x) != CONST_FIXED
-      && !CONST_DOUBLE_AS_INT_P (x))
+  if ((!CONST_SCALAR_INT_P (x)) && GET_CODE (x) != CONST_FIXED)
     return x;
   gcc_assert (mode != VOIDmode);
   return gen_rtx_CONST (mode, x);
@@ -1103,15 +1117,23 @@ cselib_hash_rtx (rtx x, int create, enum
       hash += ((unsigned) CONST_INT << 7) + INTVAL (x);
       return hash ? hash : (unsigned int) CONST_INT;
 
+    case CONST_WIDE_INT:
+      {
+	int i;
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hash += CONST_WIDE_INT_ELT (x, i);
+      }
+      return hash;
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
 	 the integers representing the constant.  */
       hash += (unsigned) code + (unsigned) GET_MODE (x);
-      if (GET_MODE (x) != VOIDmode)
-	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      else
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	hash += ((unsigned) CONST_DOUBLE_LOW (x)
 		 + (unsigned) CONST_DOUBLE_HIGH (x));
+      else
+	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       return hash ? hash : (unsigned int) CONST_DOUBLE;
 
     case CONST_FIXED:
Index: gcc/explow.c
===================================================================
--- gcc/explow.c	(revision 191978)
+++ gcc/explow.c	(working copy)
@@ -97,38 +97,9 @@ plus_constant (enum machine_mode mode, r
 
   switch (code)
     {
-    case CONST_INT:
-      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
-	{
-	  double_int di_x = double_int::from_shwi (INTVAL (x));
-	  double_int di_c = double_int::from_shwi (c);
-
-	  bool overflow;
-	  double_int v = di_x.add_with_sign (di_c, false, &overflow);
-	  if (overflow)
-	    gcc_unreachable ();
-
-	  return immed_double_int_const (v, VOIDmode);
-	}
-
-      return GEN_INT (INTVAL (x) + c);
-
-    case CONST_DOUBLE:
-      {
-	double_int di_x = double_int::from_pair (CONST_DOUBLE_HIGH (x),
-						 CONST_DOUBLE_LOW (x));
-	double_int di_c = double_int::from_shwi (c);
-
-	bool overflow;
-	double_int v = di_x.add_with_sign (di_c, false, &overflow);
-	if (overflow)
-	  /* Sorry, we have no way to represent overflows this wide.
-	     To fix, add constant support wider than CONST_DOUBLE.  */
-	  gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT);
-
-	return immed_double_int_const (v, VOIDmode);
-      }
-
+    CASE_CONST_SCALAR_INT:
+      return immed_wide_int_const (wide_int::from_rtx (x, mode)
+				   + wide_int::from_shwi (c, mode));
     case MEM:
       /* If this is a reference to the constant pool, try replacing it with
 	 a reference to a new constant.  If the resulting address isn't
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(revision 191978)
+++ gcc/varasm.c	(working copy)
@@ -3358,6 +3358,7 @@ const_rtx_hash_1 (rtx *xp, void *data)
   enum rtx_code code;
   hashval_t h, *hp;
   rtx x;
+  int i;
 
   x = *xp;
   code = GET_CODE (x);
@@ -3368,12 +3369,12 @@ const_rtx_hash_1 (rtx *xp, void *data)
     {
     case CONST_INT:
       hwi = INTVAL (x);
+
     fold_hwi:
       {
 	int shift = sizeof (hashval_t) * CHAR_BIT;
 	const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t);
-	int i;
-
+	
 	h ^= (hashval_t) hwi;
 	for (i = 1; i < n; ++i)
 	  {
@@ -3383,8 +3384,17 @@ const_rtx_hash_1 (rtx *xp, void *data)
       }
       break;
 
+    case CONST_WIDE_INT:
+      hwi = GET_MODE_PRECISION (mode);
+      {
+	int i;
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hwi ^= CONST_WIDE_INT_ELT (x, i);
+	goto fold_hwi;
+      }
+
     case CONST_DOUBLE:
-      if (mode == VOIDmode)
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && mode == VOIDmode)
 	{
 	  hwi = CONST_DOUBLE_LOW (x) ^ CONST_DOUBLE_HIGH (x);
 	  goto fold_hwi;
Index: gcc/hwint.c
===================================================================
--- gcc/hwint.c	(revision 191978)
+++ gcc/hwint.c	(working copy)
@@ -112,6 +112,29 @@ ffs_hwi (unsigned HOST_WIDE_INT x)
 int
 popcount_hwi (unsigned HOST_WIDE_INT x)
 {
+  /* Compute the popcount of a HWI using the algorithm from
+     Hacker's Delight.  */
+#if HOST_BITS_PER_WIDE_INT == 32
+  x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
+  x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+  x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
+  x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
+  x = (x & 0x0000FFFF) + ((x >>16) & 0x0000FFFF);
+#elif HOST_BITS_PER_WIDE_INT == 64
+  x = (x & HOST_WIDE_INT_C (0x5555555555555555) 
+       + ((x >> 1) & HOST_WIDE_INT_C (0x5555555555555555);
+  x = (x & HOST_WIDE_INT_C (0x3333333333333333) 
+       + ((x >> 2) & HOST_WIDE_INT_C (0x3333333333333333);
+  x = (x & HOST_WIDE_INT_C (0x0F0F0F0F0F0F0F0F) 
+       + ((x >> 4) & HOST_WIDE_INT_C (0x0F0F0F0F0F0F0F0F);
+  x = (x & HOST_WIDE_INT_C (0x00FF00FF00FF00FF) 
+       + ((x >> 8) & HOST_WIDE_INT_C (0x00FF00FF00FF00FF);
+  x = (x & HOST_WIDE_INT_C (0x0000FFFF0000FFFF) 
+       + ((x >>16) & HOST_WIDE_INT_C (0x0000FFFF0000FFFF);
+  x = (x & HOST_WIDE_INT_C (0x00000000FFFFFFFF) 
+       + ((x >>32) & HOST_WIDE_INT_C (0x00000000FFFFFFFF);
+  return x;
+#else
   int i, ret = 0;
   size_t bits = sizeof (x) * CHAR_BIT;
 
@@ -122,6 +145,7 @@ popcount_hwi (unsigned HOST_WIDE_INT x)
     }
 
   return ret;
+#endif
 }
 
 #endif /* GCC_VERSION < 3004 */
Index: gcc/hwint.h
===================================================================
--- gcc/hwint.h	(revision 191978)
+++ gcc/hwint.h	(working copy)
@@ -77,6 +77,40 @@ extern char sizeof_long_long_must_be_8[s
 # endif
 #endif
 
+/* Print support for half a host wide int.  */
+#define HOST_BITS_PER_HALF_WIDE_INT (HOST_BITS_PER_WIDE_INT / 2)
+#if HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_LONG
+# define HOST_HALF_WIDE_INT long
+# define HOST_HALF_WIDE_INT_PRINT HOST_LONG_FORMAT
+# define HOST_HALF_WIDE_INT_PRINT_C "L"
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_INT
+# define HOST_HALF_WIDE_INT int
+# define HOST_HALF_WIDE_INT_PRINT ""
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_SHORT
+# define HOST_HALF_WIDE_INT short
+# define HOST_HALF_WIDE_INT_PRINT "h"
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#else
+#error Please add support for HOST_HALF_WIDE_INT
+#endif
+
+
 #define HOST_WIDE_INT_1 HOST_WIDE_INT_C(1)
 
 /* This is a magic identifier which allows GCC to figure out the type
@@ -94,9 +128,13 @@ typedef HOST_WIDE_INT __gcc_host_wide_in
 # if HOST_BITS_PER_WIDE_INT == 64
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%016" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%016" HOST_LONG_FORMAT "x"
 # else
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%08" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%08" HOST_LONG_FORMAT "x"
 # endif
 #else
 # define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT
@@ -104,6 +142,8 @@ typedef HOST_WIDE_INT __gcc_host_wide_in
   /* We can assume that 'long long' is at least 64 bits.  */
 # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
     "0x%" HOST_LONG_LONG_FORMAT "x%016" HOST_LONG_LONG_FORMAT "x"
+# define HOST_WIDE_INT_PRINT_PADDED_HEX \
+    "%016" HOST_LONG_LONG_FORMAT "x"
 #endif /* HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG */
 
 #define HOST_WIDE_INT_PRINT_DEC "%" HOST_WIDE_INT_PRINT "d"
Index: gcc/postreload.c
===================================================================
--- gcc/postreload.c	(revision 191978)
+++ gcc/postreload.c	(working copy)
@@ -286,27 +286,25 @@ reload_cse_simplify_set (rtx set, rtx in
 #ifdef LOAD_EXTEND_OP
 	  if (extend_op != UNKNOWN)
 	    {
-	      HOST_WIDE_INT this_val;
+	      wide_int result;
 
-	      /* ??? I'm lazy and don't wish to handle CONST_DOUBLE.  Other
-		 constants, such as SYMBOL_REF, cannot be extended.  */
-	      if (!CONST_INT_P (this_rtx))
+	      if (!CONST_SCALAR_INT_P (this_rtx))
 		continue;
 
-	      this_val = INTVAL (this_rtx);
 	      switch (extend_op)
 		{
 		case ZERO_EXTEND:
-		  this_val &= GET_MODE_MASK (GET_MODE (src));
+		  result = (wide_int::from_rtx (this_rtx, GET_MODE (src))
+			    .zext (word_mode));
 		  break;
 		case SIGN_EXTEND:
-		  /* ??? In theory we're already extended.  */
-		  if (this_val == trunc_int_for_mode (this_val, GET_MODE (src)))
-		    break;
+		  result = (wide_int::from_rtx (this_rtx, GET_MODE (src))
+			    .sext (word_mode));
+		  break;
 		default:
 		  gcc_unreachable ();
 		}
-	      this_rtx = GEN_INT (this_val);
+	      this_rtx = immed_wide_int_const (result);
 	    }
 #endif
 	  this_cost = set_src_cost (this_rtx, speed);
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c	(revision 191978)
+++ gcc/var-tracking.c	(working copy)
@@ -3386,6 +3386,23 @@ loc_cmp (rtx x, rtx y)
       default:
 	gcc_unreachable ();
       }
+  if (CONST_WIDE_INT_P (x))
+    {
+      /* Compare the vector length first.  */
+      if (CONST_WIDE_INT_NUNITS (x) >= CONST_WIDE_INT_NUNITS (y))
+	return 1;
+      else if (CONST_WIDE_INT_NUNITS (x) < CONST_WIDE_INT_NUNITS (y))
+	return -1;
+
+      /* Compare the vectors elements.  */;
+      for (j = CONST_WIDE_INT_NUNITS (x) - 1; j >= 0 ; j--)
+	{
+	  if (CONST_WIDE_INT_ELT (x, j) < CONST_WIDE_INT_ELT (y, j))
+	    return -1;
+	  if (CONST_WIDE_INT_ELT (x, j) > CONST_WIDE_INT_ELT (y, j))
+	    return 1;
+	}
+    }
 
   return 0;
 }
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 191978)
+++ gcc/tree.c	(working copy)
@@ -1067,6 +1067,21 @@ double_int_to_tree (tree type, double_in
   return build_int_cst_wide (type, cst.low, cst.high);
 }
 
+/* Constructs tree in type TYPE from with value given by CST.  Signedness
+   of CST is assumed to be the same as the signedness of TYPE.  */
+
+tree
+wide_int_to_tree (tree type, const wide_int &cst)
+{
+  wide_int v;
+  if (TYPE_UNSIGNED (type))
+    v = cst.zext (TYPE_PRECISION (type));
+  else
+    v = cst.sext (TYPE_PRECISION (type));
+
+  return build_int_cst_wide (type, v.elt (0), v.elt (1));
+}
+
 /* Returns true if CST fits into range of TYPE.  Signedness of CST is assumed
    to be the same as the signedness of TYPE.  */
 
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 191978)
+++ gcc/tree.h	(working copy)
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3.
 #include "vec.h"
 #include "vecir.h"
 #include "double-int.h"
+#include "wide-int.h"
 #include "real.h"
 #include "fixed-value.h"
 #include "alias.h"
@@ -4719,6 +4720,10 @@ tree_to_double_int (const_tree cst)
 }
 
 extern tree double_int_to_tree (tree, double_int);
+#ifndef GENERATOR_FILE
+extern tree wide_int_to_tree (tree type, const wide_int &cst);
+#endif
+
 extern bool double_int_fits_to_tree_p (const_tree, double_int);
 extern tree force_fit_type_double (tree, double_int, int, bool);
 
Index: gcc/gensupport.c
===================================================================
--- gcc/gensupport.c	(revision 191978)
+++ gcc/gensupport.c	(working copy)
@@ -1671,7 +1671,13 @@ static const struct std_pred_table std_p
   {"scratch_operand", false, false, {SCRATCH, REG}},
   {"immediate_operand", false, true, {UNKNOWN}},
   {"const_int_operand", false, false, {CONST_INT}},
+#if TARGET_SUPPORTS_WIDE_INT
+  {"const_wide_int_operand", false, false, {CONST_WIDE_INT}},
+  {"const_scalar_int_operand", false, false, {CONST_INT, CONST_WIDE_INT}},
+  {"const_double_operand", false, false, {CONST_DOUBLE}},
+#else
   {"const_double_operand", false, false, {CONST_INT, CONST_DOUBLE}},
+#endif
   {"nonimmediate_operand", false, false, {SUBREG, REG, MEM}},
   {"nonmemory_operand", false, true, {SUBREG, REG}},
   {"push_operand", false, false, {MEM}},
Index: gcc/read-rtl.c
===================================================================
--- gcc/read-rtl.c	(revision 191978)
+++ gcc/read-rtl.c	(working copy)
@@ -679,6 +679,29 @@ validate_const_int (const char *string)
     fatal_with_file_and_line ("invalid decimal constant \"%s\"\n", string);
 }
 
+static void
+validate_const_wide_int (const char *string)
+{
+  const char *cp;
+  int valid = 1;
+
+  cp = string;
+  while (*cp && ISSPACE (*cp))
+    cp++;
+  /* Skip the leading 0x.  */
+  if (cp[0] == '0' || cp[1] == 'x')
+    cp += 2;
+  else
+    valid = 0;
+  if (*cp == 0)
+    valid = 0;
+  for (; *cp; cp++)
+    if (! ISXDIGIT (*cp))
+      valid = 0;
+  if (!valid)
+    fatal_with_file_and_line ("invalid hex constant \"%s\"\n", string);
+}
+
 /* Record that PTR uses iterator ITERATOR.  */
 
 static void
@@ -1064,6 +1087,56 @@ read_rtx_code (const char *code_name)
 	gcc_unreachable ();
       }
 
+  if (CONST_WIDE_INT_P (return_rtx))
+    {
+      read_name (&name);
+      validate_const_wide_int (name.string);
+      {
+	hwivec hwiv;
+	const char *s = name.string;
+	int len;
+	int index = 0;
+	int gs = HOST_BITS_PER_WIDE_INT/4;
+	int pos;
+	char * buf = XALLOCAVEC (char, gs + 1);
+	unsigned HOST_WIDE_INT wi;
+	int wlen;
+
+	/* Skip the leading spaces.  */
+	while (*s && ISSPACE (*s))
+	  s++;
+
+	/* Skip the leading 0x.  */
+	gcc_assert (s[0] == '0');
+	gcc_assert (s[1] == 'x');
+	s += 2;
+
+	len = strlen (s);
+	pos = len - gs;
+	wlen = (len + gs - 1)/gs;	/* Number of words needed */
+
+	return_rtx = const_wide_int_alloc (wlen);
+
+	hwiv = CONST_WIDE_INT_VEC (return_rtx);
+	while (pos > 0)
+	  {
+#if HOST_BITS_PER_WIDE_INT == 64
+	    sscanf (s + pos, "%16" HOST_WIDE_INT_PRINT "x", &wi);
+#else
+	    sscanf (s + pos, "%8" HOST_WIDE_INT_PRINT "x", &wi);
+#endif
+	    XHWIVEC_ELT (hwiv, index++) = wi;
+	    pos -= gs;
+	  }
+	strncpy (buf, s, gs - pos);
+	buf [gs - pos] = 0;
+	sscanf (buf, "%" HOST_WIDE_INT_PRINT "x", &wi);
+	XHWIVEC_ELT (hwiv, index++) = wi;
+	/* TODO: After reading, do we want to canonicalize with:
+	   value = lookup_const_wide_int (value); ? */
+      }
+    }
+
   c = read_skip_spaces ();
   /* Syntactic sugar for AND and IOR, allowing Lisp-like
      arbitrary number of arguments for them.  */
Index: gcc/cse.c
===================================================================
--- gcc/cse.c	(revision 191978)
+++ gcc/cse.c	(working copy)
@@ -2335,15 +2335,23 @@ hash_rtx_cb (const_rtx x, enum machine_m
                + (unsigned int) INTVAL (x));
       return hash;
 
+    case CONST_WIDE_INT:
+      {
+	int i;
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hash += CONST_WIDE_INT_ELT (x, i);
+      }
+      return hash;
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
 	 the integers representing the constant.  */
       hash += (unsigned int) code + (unsigned int) GET_MODE (x);
-      if (GET_MODE (x) != VOIDmode)
-	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      else
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	hash += ((unsigned int) CONST_DOUBLE_LOW (x)
 		 + (unsigned int) CONST_DOUBLE_HIGH (x));
+      else
+	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       return hash;
 
     case CONST_FIXED:
@@ -3759,6 +3767,7 @@ equiv_constant (rtx x)
 
       /* See if we previously assigned a constant value to this SUBREG.  */
       if ((new_rtx = lookup_as_function (x, CONST_INT)) != 0
+	  || (new_rtx = lookup_as_function (x, CONST_WIDE_INT)) != 0
           || (new_rtx = lookup_as_function (x, CONST_DOUBLE)) != 0
           || (new_rtx = lookup_as_function (x, CONST_FIXED)) != 0)
         return new_rtx;
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(revision 191978)
+++ gcc/dwarf2out.c	(working copy)
@@ -1327,6 +1327,9 @@ dw_val_equal_p (dw_val_node *a, dw_val_n
       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;
@@ -1578,6 +1581,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 += (loc->dw_loc_oprnd2.v.val_wide.full_len ()
+		     * HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT);
+	    break;
 	  default:
 	    gcc_unreachable ();
 	  }
@@ -1755,6 +1762,20 @@ output_loc_operands (dw_loc_descr_ref lo
 				 second, NULL);
 	  }
 	  break;
+	case dw_val_class_wide_int:
+	  {
+	    int i;
+	    int len = val2->v.val_wide.full_len ();
+	    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);
@@ -1957,6 +1978,21 @@ output_loc_operands (dw_loc_descr_ref lo
 	      dw2_asm_output_data (l, second, NULL);
 	    }
 	    break;
+	  case dw_val_class_wide_int:
+	    {
+	      int i;
+	      int len = val2->v.val_wide.full_len ();
+	      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 ();
 	  }
@@ -3060,7 +3096,7 @@ static void add_AT_location_description
 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 (wide_int *, unsigned char *);
 static void insert_float (const_rtx, unsigned char *);
 static rtx rtl_for_decl_location (tree);
 static bool add_location_or_const_value_attribute (dw_die_ref, tree, bool,
@@ -3557,6 +3593,20 @@ AT_unsigned (dw_attr_ref a)
 /* Add an unsigned double integer attribute value to a DIE.  */
 
 static inline void
+add_AT_wide (dw_die_ref die, enum dwarf_attribute attr_kind,
+	     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 = w;
+  add_dwarf_attr (die, &attr);
+}
+
+/* Add an unsigned double integer attribute value to a DIE.  */
+
+static inline void
 add_AT_double (dw_die_ref die, enum dwarf_attribute attr_kind,
 	       HOST_WIDE_INT high, unsigned HOST_WIDE_INT low)
 {
@@ -4867,6 +4917,19 @@ 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;
@@ -5022,6 +5085,9 @@ attr_checksum (dw_attr_ref at, struct md
     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 (at->dw_attr_val.v.val_vec);
       break;
@@ -5292,6 +5358,12 @@ attr_checksum_ordered (enum dwarf_tag ta
       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 (sizeof (at->dw_attr_val.v.val_vec));
@@ -5756,6 +5828,8 @@ same_dw_val_p (const dw_val_node *v1, co
     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)
@@ -7207,6 +7281,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 += (a->dw_attr_val.v.val_wide.full_len ()
+		   * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
+	  if (a->dw_attr_val.v.val_wide.full_len () * 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)
@@ -7531,6 +7612,20 @@ value_format (dw_attr_ref a)
 	default:
 	  return DW_FORM_block1;
 	}
+    case dw_val_class_wide_int:
+      switch (a->dw_attr_val.v.val_wide.full_len () * 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))
@@ -7878,6 +7973,32 @@ output_die (dw_die_ref die)
 	  }
 	  break;
 
+	case dw_val_class_wide_int:
+	  {
+	    int i;
+	    int len = a->dw_attr_val.v.val_wide.full_len ();
+	    int l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
+	    if (len * HOST_BITS_PER_WIDE_INT > 64)
+	      dw2_asm_output_data (1, a->dw_attr_val.v.val_wide.full_len () * 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;
@@ -10846,9 +10967,8 @@ clz_loc_descriptor (rtx rtl, enum machin
     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 
+      (wide_int::set_bit_in_zero (GET_MODE_PRECISION (mode) - 1, 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
@@ -11784,7 +11904,16 @@ mem_loc_descriptor (rtx rtl, enum machin
 	  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
@@ -11796,13 +11925,26 @@ mem_loc_descriptor (rtx rtl, enum machin
 	      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
+	    = wide_int::from_rtx (rtl, mode);
 	}
       break;
 
@@ -12273,7 +12415,15 @@ loc_descriptor (rtx rtl, enum machine_mo
 	     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
@@ -12285,12 +12435,26 @@ loc_descriptor (rtx rtl, enum machine_mo
 	      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))
+	{
+	  gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
+
+	  /* Note that a CONST_DOUBLE rtx could represent either an integer
+	     or a floating-point constant.  A CONST_DOUBLE is used whenever
+	     the constant requires more than one word in order to be
+	     adequately represented.  We output CONST_DOUBLEs as blocks.  */
+	  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
+	    = wide_int::from_rtx (rtl, mode);
 	}
       break;
 
@@ -12306,6 +12470,7 @@ loc_descriptor (rtx rtl, enum machine_mo
 	    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))
@@ -12314,15 +12479,8 @@ loc_descriptor (rtx rtl, enum machine_mo
 	      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);
-		    }
+		  wide_int val = wide_int::from_rtx (elt, imode);
+		  insert_wide_int (&val, p);
 		}
 	      break;
 
@@ -12349,8 +12507,8 @@ loc_descriptor (rtx rtl, enum machine_mo
 
     case CONST:
       if (mode == VOIDmode
-	  || GET_CODE (XEXP (rtl, 0)) == CONST_INT
-	  || GET_CODE (XEXP (rtl, 0)) == CONST_DOUBLE
+	  || CONST_SCALAR_INT_P (XEXP (rtl, 0))
+	  || CONST_DOUBLE_AS_FLOAT_P (XEXP (rtl, 0))
 	  || GET_CODE (XEXP (rtl, 0)) == CONST_VECTOR)
 	{
 	  loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
@@ -13960,22 +14118,27 @@ extract_int (const unsigned char *src, u
   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 (wide_int *val, unsigned char *dest)
 {
-  unsigned char *p0 = dest;
-  unsigned char *p1 = dest + sizeof (HOST_WIDE_INT);
+  int i;
 
   if (WORDS_BIG_ENDIAN)
-    {
-      p0 = p1;
-      p1 = dest;
-    }
-
-  insert_int ((HOST_WIDE_INT) val.low, sizeof (HOST_WIDE_INT), p0);
-  insert_int ((HOST_WIDE_INT) val.high, sizeof (HOST_WIDE_INT), p1);
+    for (i = val->full_len () - 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 < val->full_len (); 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.  */
@@ -14020,6 +14183,11 @@ add_const_value_attribute (dw_die_ref di
       }
       return true;
 
+    case CONST_WIDE_INT:
+      add_AT_wide (die, DW_AT_const_value,
+		   wide_int::from_rtx (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
@@ -14028,7 +14196,10 @@ add_const_value_attribute (dw_die_ref di
       {
 	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);
@@ -14036,9 +14207,6 @@ add_const_value_attribute (dw_die_ref di
 	    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;
 
@@ -14051,6 +14219,7 @@ add_const_value_attribute (dw_die_ref di
 	  (length * elt_size);
 	unsigned int i;
 	unsigned char *p;
+	enum machine_mode imode = GET_MODE_INNER (mode);
 
 	switch (GET_MODE_CLASS (mode))
 	  {
@@ -14058,15 +14227,8 @@ add_const_value_attribute (dw_die_ref di
 	    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);
-		  }
+		wide_int val = wide_int::from_rtx (elt, imode);
+		insert_wide_int (&val, p);
 	      }
 	    break;
 
@@ -21863,6 +22025,9 @@ hash_loc_operands (dw_loc_descr_ref loc,
 	  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;
@@ -21941,6 +22106,9 @@ hash_loc_operands (dw_loc_descr_ref loc,
 	    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 ();
 	  }
@@ -22086,6 +22254,8 @@ compare_loc_operands (dw_loc_descr_ref x
 	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:
@@ -22122,6 +22292,8 @@ compare_loc_operands (dw_loc_descr_ref x
 	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 ();
 	}
Index: gcc/dwarf2out.h
===================================================================
--- gcc/dwarf2out.h	(revision 191978)
+++ gcc/dwarf2out.h	(working copy)
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.
 #define GCC_DWARF2OUT_H 1
 
 #include "dwarf2.h"	/* ??? Remove this once only used by dwarf2foo.c.  */
+#include "wide-int.h"
 
 typedef struct die_struct *dw_die_ref;
 typedef const struct die_struct *const_dw_die_ref;
@@ -143,6 +144,7 @@ enum dw_val_class
   dw_val_class_const,
   dw_val_class_unsigned_const,
   dw_val_class_const_double,
+  dw_val_class_wide_int,
   dw_val_class_vec,
   dw_val_class_flag,
   dw_val_class_die_ref,
@@ -181,6 +183,7 @@ typedef struct GTY(()) dw_val_struct {
       HOST_WIDE_INT GTY ((default)) val_int;
       unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
       double_int GTY ((tag ("dw_val_class_const_double"))) val_double;
+      wide_int GTY ((tag ("dw_val_class_wide_int"))) val_wide;
       dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
       struct dw_val_die_union
 	{
Index: gcc/wide-int.c
===================================================================
--- gcc/wide-int.c	(revision 0)
+++ gcc/wide-int.c	(revision 0)
@@ -0,0 +1,4257 @@
+/* Operations with very long integers.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hwint.h"
+#include "wide-int.h"
+#include "rtl.h"
+#include "tree.h"
+#include "dumpfile.h"
+
+#define DEBUG_WIDE_INT
+#ifdef DEBUG_WIDE_INT
+  /* Debugging routines.  */
+  static void debug_vw  (const char* name, int r, const wide_int& o0);
+  static void debug_vwh (const char* name, int r, const wide_int &o0,
+			 HOST_WIDE_INT o1);
+  static void debug_vww (const char* name, int r, const wide_int &o0,
+			 const wide_int &o1);
+  static void debug_wv (const char* name, const wide_int &r, int v0);
+  static void debug_wvv (const char* name, const wide_int &r, int v0,
+			 int v1);
+  static void debug_wvvv (const char* name, const wide_int &r, int v0,
+			  int v1, int v2);
+  static void debug_wwv (const char* name, const wide_int &r,
+			 const wide_int &o0, int v0);
+  static void debug_wwwvv (const char* name, const wide_int &r,
+			   const wide_int &o0, const wide_int &o1,
+			   int v0, int v1);
+  static void debug_ww (const char* name, const wide_int &r,
+			const wide_int &o0);
+  static void debug_www (const char* name, const wide_int &r,
+			 const wide_int &o0, const wide_int &o1);
+  static void debug_wwwv (const char* name, const wide_int &r,
+			  const wide_int &o0, const wide_int &o1,
+			  int v0);
+  static void debug_wwww (const char* name, const wide_int &r,
+			  const wide_int &o0, const wide_int &o1, 
+			  const wide_int &o2);
+#endif
+// using wide_int::;
+
+/* Debugging routines.  */
+
+/* This is the maximal size of the buffer needed for dump.  */
+const int MAX = (MAX_BITSIZE_MODE_ANY_INT / 4
+		 + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
+
+#ifdef DEBUG_WIDE_INT
+
+/*
+ * Internal utilities.
+ */
+
+/* Quantities to deal with values that hold half of a wide int.  Used
+   in multiply and divide.  */
+#define HALF_INT_MASK (((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1)
+
+#define BLOCK_OF(TARGET) ((TARGET) / HOST_BITS_PER_WIDE_INT)
+#define BLOCKS_NEEDED(PREC) \
+  (((PREC) + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+
+/*
+ * Conversion routines in and out of wide-int.
+ */
+
+/* Convert OP0 into a wide int.  If the precision is less than
+   HOST_BITS_PER_WIDE_INT, zero extend the value of the word.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode)
+{
+  wide_int result;
+  int prec = GET_MODE_PRECISION (mode);
+
+  result.mode = mode;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    op0 = sext (op0, prec);
+
+  result.val[0] = op0;
+  result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+	       "wide_int::from_shwi", result.dump (buf0), op0);
+    }
+#endif
+
+  return result;
+}
+
+/* Convert OP0 into a wide int.  If the precision is less than
+   HOST_BITS_PER_WIDE_INT, zero extend the value of the word.  The
+   overflow bit are set if the number was too large to fit in the
+   mode.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, bool *overflow)
+{
+  wide_int result;
+  int prec = GET_MODE_PRECISION (mode);
+
+  result.mode = mode;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT t = sext (op0, prec);
+      if (t != op0)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+  result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+	       "wide_int::from_shwi", result.dump (buf0), op0);
+    }
+#endif
+
+  return result;
+}
+
+/* Convert OP0 into a wide int.  If the precision is less than
+   HOST_BITS_PER_WIDE_INT, zero extend the value of the word.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode)
+{
+  wide_int result;
+  int prec = GET_MODE_PRECISION (mode);
+
+  result.mode = mode;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    op0 = zext (op0, prec);
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && prec > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+	       "wide_int::from_uhwi", result.dump (buf0), op0);
+    }
+#endif
+
+  return result;
+}
+
+/* Convert OP0 into a wide int.  If the precision is less than
+   HOST_BITS_PER_WIDE_INT, zero extend the value of the word.  The
+   overflow bit are set if the number was too large to fit in the
+   mode.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode, bool *overflow)
+{
+  wide_int result;
+  int prec = GET_MODE_PRECISION (mode);
+
+  result.mode = mode;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT t = zext (op0, prec);
+      if (t != op0)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && prec > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+	       "wide_int::from_uhwi", result.dump (buf0), op0);
+    }
+#endif
+
+  return result;
+}
+
+/* Convert a double int into a wide int.  */
+
+wide_int
+wide_int::from_double_int (enum machine_mode mode, double_int di)
+{
+  wide_int result;
+  result.mode = mode;
+  result.len = 2;
+  result.val[0] = di.low;
+  result.val[1] = di.high;
+  result.canonize ();
+  return result;
+}
+
+/* Convert a integer cst into a wide int.  */
+
+wide_int
+wide_int::from_int_cst (const_tree tcst)
+{
+#if 1
+  wide_int result;
+  tree type = TREE_TYPE (tcst);
+  int prec = TYPE_PRECISION (type);
+  HOST_WIDE_INT op = TREE_INT_CST_LOW (tcst);
+
+  result.mode = TYPE_MODE (type);
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    {
+      if (TYPE_UNSIGNED (type))
+	result.val[0] = zext (op, prec);
+      else
+	result.val[0] = sext (op, prec);
+    }
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    {
+	      op = TREE_INT_CST_HIGH (tcst);
+	      if (TYPE_UNSIGNED (type))
+		result.val[1] = zext (op, prec);
+	      else
+		result.val[1] = sext (op, prec);
+	    }
+	  else
+	    result.val[1] = TREE_INT_CST_HIGH (tcst);
+	}
+    }
+
+  if (result.len == 2)
+    result.canonize ();
+
+  return result;
+#endif
+  /* This is the code once the tree level is converted.  */
+#if 0
+  wide_int result;
+  int i;
+
+  tree type = TREE_TYPE (tcst);
+
+  result.mode = TYPE_MODE (type);
+  result.len = TREE_INT_CST_LEN (tcst);
+  for (i = 0; i < result.len; i++)
+    result.val[i] = TREE_INT_CST_ELT (tcst, i);
+
+  return result;
+#endif
+}
+
+/* Extract a constant integer from the X.  The bits of the integer are
+   returned.  */
+
+wide_int
+wide_int::from_rtx (const_rtx x, enum machine_mode mode)
+{
+  wide_int result;
+  int prec = GET_MODE_PRECISION (mode);
+
+  gcc_assert (mode != VOIDmode);
+
+  result.mode = mode;
+
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+      if ((prec & (HOST_BITS_PER_WIDE_INT - 1)) != 0)
+	result.val[0] = sext (INTVAL (x), prec);
+      else
+	result.val[0] = INTVAL (x);
+      result.len = 1;
+      break;
+
+#if TARGET_SUPPORTS_WIDE_INT
+    case CONST_WIDE_INT:
+      {
+	int i;
+	result.len = CONST_WIDE_INT_NUNITS (x);
+	
+	for (i = 0; i < result.len; i++)
+	  result.val[i] = CONST_WIDE_INT_ELT (x, i);
+      }
+      break;
+#else
+    case CONST_DOUBLE:
+      result.len = 2;
+      result.val[0] = CONST_DOUBLE_LOW (x);
+      result.val[1] = CONST_DOUBLE_HIGH (x);
+      result.canonize ();
+      break;
+#endif
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return result;
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi (int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = sext (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS is too large for
+   the mode's precision, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi () const
+{
+  return to_shwi (precision ());
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi (int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = zext (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS is too large for
+   the mode's precision, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi () const
+{
+  return to_uhwi (precision ());
+}
+
+/*
+ * Largest and smallest values in a mode.
+ */
+
+/* Produce the largest number that is represented in MODE.  The result
+   is a wide_int of MODE.  SGN must be SIGNED or UNSIGNED.  */
+
+wide_int
+wide_int::max_value (const enum machine_mode mode, Op sgn)
+{
+  return max_value (mode, GET_MODE_PRECISION (mode), sgn);
+}
+
+/* Produce the largest number that is represented in PREC.  The result
+   is a wide_int of MODE.   SGN must be SIGNED or UNSIGNED.  */
+
+wide_int
+wide_int::max_value (const enum machine_mode mode, int prec, Op sgn)
+{
+  wide_int result;
+  
+  result.mode = mode;
+
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned max is just all ones, for which the compressed
+	 rep is just a single HWI.  */ 
+      result.len = 1;
+      result.val[0] = (HOST_WIDE_INT)-1;
+    }
+  else
+    {
+      /* The signed max is all ones except the top bit.  This must be
+	 explicitly represented.  */
+      int i;
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      int shift = (small_prec == 0) 
+	? HOST_BITS_PER_WIDE_INT - 1 : small_prec - 1;
+
+      result.len = BLOCKS_NEEDED (prec);
+      for (i = 0; i < result.len - 1; i++)
+	result.val[i] = (HOST_WIDE_INT)-1;
+
+      result.val[result.len - 1] = ((HOST_WIDE_INT)1 << shift) - 1;
+    }
+  
+  return result;
+}
+
+/* Produce the smallest number that is represented in MODE. The result
+   is a wide_int of MODE.   SGN must be SIGNED or UNSIGNED.   */
+
+wide_int
+wide_int::min_value (const enum machine_mode mode, Op sgn)
+{
+  return min_value (mode, GET_MODE_PRECISION (mode), sgn);
+}
+
+/* Produce the smallest number that is represented in PREC. The result
+   is a wide_int of MODE.   SGN must be SIGNED or UNSIGNED.   */
+
+wide_int
+wide_int::min_value (const enum machine_mode mode, int prec, Op sgn)
+{
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned min is just all zeros, for which the compressed
+	 rep is just a single HWI.  */ 
+      wide_int result;
+      result.len = 1;
+      result.mode = mode;
+      result.val[0] = 0;
+      return result;
+    }
+  else
+    {
+      /* The signed min is all zeros except the top bit.  This must be
+	 explicitly represented.  */
+      return set_bit_in_zero (prec - 1, mode);
+    }
+}
+
+/*
+ * Public utilities.
+ */
+
+/* Check the upper HOST_WIDE_INTs of src to see if the length can be
+   shortened.  An upper HOST_WIDE_INT is unnecessary if it is all ones
+   or zeros and the top bit of the next lower word matches.
+
+   This function may change the representation of THIS, but does not
+   change the value that THIS represents.  It does not sign extend in
+   the case that the size of the mode is less than
+   HOST_BITS_PER_WIDE_INT.  */
+
+void
+wide_int::canonize ()
+{
+  int prec = precision ();
+  int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (prec);
+  HOST_WIDE_INT top;
+  int i;
+
+  if (len > blocks_needed)
+    len = blocks_needed;
+
+  /* Clean up the top bits for any mode that is not a multiple of a HWI.  */
+  if (len == blocks_needed && small_prec)
+    val[len - 1] = sext (val[len - 1], small_prec);
+
+  if (len == 1)
+    return;
+
+  top = val[len - 1];
+  if (top != 0 && top != (HOST_WIDE_INT)-1)
+    return;
+
+  /* At this point we know that the top is either 0 or -1.  Find the
+     first block that is not a copy of this.  */
+  for (i = len - 2; i >= 0; i--)
+    {
+      HOST_WIDE_INT x = val[i];
+      if (x != top)
+	{
+	  if (x >> (HOST_BITS_PER_WIDE_INT - 1) == top)
+	    {
+	      len = i + 1;
+	      return;
+	    }
+
+	  /* We need an extra block because the top bit block i does
+	     not match the extension.  */
+	  len = i + 2;
+	  return;
+	}
+    }
+
+  /* The number is 0 or -1.  */
+  len = 1;
+}
+
+/* Copy THIS replacing the mode with MODE.  */
+
+wide_int
+wide_int::copy (enum machine_mode mode) const
+{
+  wide_int result;
+  int prec = GET_MODE_PRECISION (mode);
+  int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (prec);
+  int i;
+
+  result.mode = mode;
+  result.len = blocks_needed < len ? blocks_needed : len;
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+
+  if (small_prec & (blocks_needed == len))
+    result.val[blocks_needed-1]
+      = sext (result.val[blocks_needed-1], small_prec);
+  return result;
+}
+
+/*
+ * public printing routines.
+ */
+
+/* Try to print the signed self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (char *buf) const
+{
+  if ((precision () <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_DEC, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decs (buf);
+  fputs (buf, file);
+}
+
+/* Try to print the unsigned self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (char *buf) const
+{
+  if ((precision () <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decu (buf);
+  fputs (buf, file);
+}
+
+void 
+wide_int::print_hex (char *buf) const
+{
+  int i = len;
+
+  if (zero_p ())
+    sprintf (buf, "0x");
+  else
+    {
+      if (neg_p ())
+	{
+	  int j;
+	  /* If the number is negative, we may need to pad value with
+	     0xFFF...  because the leading elements may be missing and
+	     we do not print a '-' with hex.  */
+	  for (j = BLOCKS_NEEDED (precision ()); j > i; j--)
+	    buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, (HOST_WIDE_INT) -1);
+	    
+	}
+      else
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_HEX, val [--i]);
+      while (-- i >= 0)
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, val [i]);
+    }
+}
+
+/* Print one big hex number to FILE.  Note that some assemblers may not
+   accept this for large modes.  */
+void 
+wide_int::print_hex (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_hex (buf);
+  fputs (buf, file);
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently singed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+bool
+wide_int::operator == (const wide_int &op1) const
+{
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  int prec = precision ();
+  bool result;
+
+  gcc_assert (mode == op1.mode);
+
+  if (this == &op1)
+    {
+      result = true;
+      goto ex;
+    }
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << prec) - 1;
+      result = (val[0] & mask) == (op1.val[0] & mask);
+      goto ex;
+    }
+
+  while (l0 > l1)
+    if (val[l0--] != op1.sign_mask ())
+      {
+	result = false;
+	goto ex;
+      }
+
+  while (l1 > l0)
+    if (op1.val[l1--] != sign_mask ())
+      {
+	result = false;
+	goto ex;
+      }
+
+  while (l0 >= 0)
+    if (val[l0--] != op1.val[l1--])
+      {
+	result = false;
+	goto ex;
+      }
+
+  result = true;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("operator ==", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS > OP1 using signed comparisons.  */
+
+bool
+wide_int::gts_p (const HOST_WIDE_INT op1) const
+{
+  int prec = precision ();
+  bool result;
+
+  if (prec <= HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] > wide_int::sext(op1, prec);
+      goto ex;
+    }
+  
+  result = !neg_p ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int::gts_p", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS > OP1 using unsigned comparisons.  */
+
+bool
+wide_int::gtu_p (const unsigned HOST_WIDE_INT op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int prec = precision ();
+  bool result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      x0 = zext (val[0], prec);
+      x1 = zext (op1, prec);
+
+      result = x0 > x1;
+    }
+  else
+    result = true;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int::gtu_p", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p (const HOST_WIDE_INT op1) const
+{
+  int prec = precision ();
+  bool result;
+
+  if (prec <= HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] < wide_int::sext(op1, prec);
+      goto ex;
+    }
+  
+  result = neg_p ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int::lts_p", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p (const wide_int &op1) const
+{
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  int prec = precision ();
+  bool result;
+
+  gcc_assert (mode == op1.mode);
+
+  if (this == &op1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] < op1.val[0];
+      goto ex;
+    }
+
+  while (l0 > l1)
+    if (val[l0--] < op1.sign_mask ())
+      {
+	result = true;
+	goto ex;
+      }
+
+  while (l1 > l0)
+    if (sign_mask () < op1.val[l1--])
+      {
+	result = true;
+	goto ex;
+      }
+
+  while (l0 >= 0)
+    if (val[l0--] < op1.val[l1--])
+      {
+	result = true;
+	goto ex;
+      }
+
+  result = false;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int::lts_p", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p (const unsigned HOST_WIDE_INT op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int prec = precision ();
+  bool result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      x0 = zext (val[0], prec);
+      x1 = zext (op1, prec);
+
+      result = x0 < x1;
+    }
+  else
+    result = false;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int::ltu_p", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  int prec = precision ();
+  bool result;
+
+  gcc_assert (mode == op1.mode);
+
+  if (this == &op1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    {
+      x0 = zext (val[0], prec);
+      x1 = zext (op1.val[0], prec);
+
+      result = x0 < x1;
+      goto ex;
+    }
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1.sign_mask ();
+      if (x0 < x1)
+	{
+	  result = true;
+	  goto ex;
+	}
+    }
+
+  while (l1 > l0)
+    {
+      x0 = sign_mask ();
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	{
+	  result = true;
+	  goto ex;
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	{
+	  result = true;
+	  goto ex;
+	}
+    }
+
+  result = false;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int::ltu_p", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p (int prec) const
+{
+  int i;
+  HOST_WIDE_INT x;
+  int small_prec;
+  bool result;
+
+  if (BLOCKS_NEEDED (prec) != len)
+    {
+      result = false;
+      goto ex;
+    }
+
+  for (i=0; i < len - 1; i++)
+    if (val[i] != 0)
+      {
+	result = false;
+	goto ex;
+      }
+
+  x = val[len - 1];
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec)
+    x = x << (HOST_BITS_PER_WIDE_INT - small_prec);
+
+  result = x == ((HOST_WIDE_INT)1) << (HOST_BITS_PER_WIDE_INT - 1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int::only_sign_bit_p", result, *this);
+#endif
+
+  return result;
+}
+
+bool
+wide_int::only_sign_bit_p () const
+{
+  int prec = precision ();
+  return only_sign_bit_p (prec);
+}
+
+/* Returns true if THIS fits into range of TYPE.  Signedness of OP0 is
+   assumed to be the same as the signedness of TYPE.  */
+
+bool
+wide_int::fits_to_tree_p (const_tree type) const
+{
+  int type_prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return fits_u_p (type_prec);
+  else
+    return fits_s_p (type_prec);
+}
+
+/* Returns true of THIS fits in the unsigned range of precision.  */
+
+bool
+wide_int::fits_s_p (int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision () <= prec)
+    return true;
+
+  return *this == sext (prec);
+}
+
+
+/* Returns true if THIS fits into range of TYPE.  */
+
+bool
+wide_int::fits_u_p (int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision () <= prec)
+    return true;
+
+  return *this == zext (prec);
+}
+
+/*
+ * Extension.
+ */
+
+/* Sign extend THIS starting at OFFSET within the precision of the mode.  */
+
+wide_int
+wide_int::sext (int offset) const
+{
+  wide_int result;
+  int off;
+  int prec = precision ();
+
+  gcc_assert (prec >= offset);
+
+  result.mode = mode;
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[0] = sext (val[0], offset);
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::sext", result, *this, offset);
+#endif
+
+      return result;
+    }
+
+  if (prec == offset)
+    {
+      result = copy (mode);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::sext", result, *this, offset);
+#endif
+      return result;
+    }
+
+  result = decompress (offset, mode);
+
+  /* Now we can do the real sign extension.  */
+  off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  if (off)
+    {
+      int block = BLOCK_OF (offset);
+      result.val[block] = sext (val[block], off);
+      result.len = block + 1;
+    }
+  /* We never need an extra element for sign extended values.  */
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::sext", result, *this, offset);
+#endif
+
+  return result;
+}
+
+/* Sign extend THIS to mode M.  */
+
+wide_int
+wide_int::sext (enum machine_mode m) const
+{
+  if (GET_MODE_PRECISION (m) >= precision ())
+    /* Assuming that MODE is larger than op0-> mode, the compressed
+       value of op0 and the result will be the same.  The only thing
+       that is different is that the mode of the result will be
+       different.  */
+    return copy (m);
+
+  return truncate (m);
+}
+
+/* Zero extend THIS starting at OFFSET within the precision of the mode.  */
+
+wide_int
+wide_int::zext (int offset) const
+{
+  wide_int result;
+  int off;
+  int block;
+  int prec = precision ();
+
+  gcc_assert (prec >= offset);
+
+  result.mode = mode;
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[0] = zext (val[0], offset);
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::zext", result, *this, offset);
+#endif
+
+      return result;
+    }
+
+  if (prec == offset)
+    {
+      result = copy (mode);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::zext", result, *this, offset);
+#endif
+      return result;
+    }
+
+  result = decompress (offset, mode);
+
+  /* Now we can do the real zero extension.  */
+  off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  block = BLOCK_OF (offset);
+  if (off)
+    {
+      result.val[block] = zext (val[block], off);
+      result.len = block + 1;
+    }
+  else
+    /* See if we need an extra zero element to satisfy the compression
+       rule.  */
+    if (val[block - 1] < 0 && offset < prec)
+      {
+	result.val[block] = 0;
+	result.len += 1;
+      }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::zext", result, *this, offset);
+#endif
+
+  return result;
+}
+
+/* Zero extend THIS to mode M.  */
+
+wide_int
+wide_int::zext (enum machine_mode m) const
+{
+  wide_int result;
+  int off;
+  int block;
+  int op0_prec = precision ();
+  int res_prec = GET_MODE_PRECISION (m);
+
+  gcc_assert (res_prec >= op0_prec);
+
+  result.mode = m;
+
+  if (res_prec < HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[0] = zext (val[0], op0_prec);
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::zext", result, *this, res_prec);
+#endif
+      return result;
+    }
+
+  result = decompress (op0_prec, m);
+
+  /* Now we can do the real zero extension.  */
+  off = op0_prec & (HOST_BITS_PER_WIDE_INT - 1);
+  block = BLOCK_OF (op0_prec);
+  if (off)
+    {
+      result.val[block] = zext (val[block], off);
+      result.len = block + 1;
+    }
+  else
+    /* See if we need an extra zero element to satisfy the compression
+       rule.  */
+    if (val[block - 1] < 0 && op0_prec < res_prec)
+      {
+	result.val[block] = 0;
+	result.len += 1;
+      }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::zext", result, *this, res_prec);
+#endif
+
+  return result;
+}
+
+/*
+ * Masking, inserting, shifting, rotating.
+ */
+
+/* Return a value with a one bit inserted in THIS at BITPOS.  */
+
+wide_int
+wide_int::set_bit (int bitpos) const
+{
+  wide_int result;
+  int i, j;
+
+  if (bitpos >= precision ())
+    result = copy (mode);
+  else
+    {
+      result = decompress (bitpos, mode);
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::set_bit", result, *this, bitpos);
+#endif
+
+  return result;
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with MODE.  */
+
+wide_int
+wide_int::set_bit_in_zero (int bitpos, enum machine_mode mode)
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (bitpos);
+  int i, j;
+
+  result.mode = mode;
+  if (bitpos >= GET_MODE_PRECISION (mode))
+    {
+      result.len = 1;
+      result.val[0] = 0;
+    }
+  else
+    {
+      result.len = blocks_needed;
+      for (i = 0; i < blocks_needed; i++)
+	result.val[i] = 0;
+      
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wv ("wide_int::set_bit_in_zero", result, bitpos);
+#endif
+
+  return result;
+}
+
+/* Insert WIDTH bits from OP0 into THIS starting at START.  */
+
+wide_int
+wide_int::insert (const wide_int &op0, int start, int width) const
+{
+  wide_int result;
+  wide_int mask;
+  wide_int tmp;
+  int prec = precision ();
+
+  if (start + width >= prec) 
+    {
+      width = prec - start;
+      if (width < 0)
+	{
+	  width = 0;
+	  start = prec;
+	}
+    }
+
+  mask = shifted_mask (start, width, false, mode);
+  tmp = op0.lshift (start, NONE, mode);
+  result = tmp & mask;
+
+  tmp = and_not (mask);
+  result = result | tmp;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwwvv ("wide_int::insert", result, *this, op0, start, width);
+#endif
+
+  return result;
+}
+
+/* bswap THIS.  */
+
+wide_int
+wide_int::bswap () const
+{
+  wide_int result;
+  int i, s;
+  int end;
+  int prec = precision ();
+  int len = BLOCKS_NEEDED (prec);
+  HOST_WIDE_INT mask = sign_mask ();
+
+  /* This is not a well defined operation if the precision is not a
+     multiple of 8.  */
+  gcc_assert ((prec & 0x7) == 0);
+
+  result.mode = mode;
+  result.len = len;
+
+  for (i = 0; i < len; i++)
+    result.val[0] = mask;
+
+  /* Only swap the bytes that are not the padding.  */
+  if ((prec & (HOST_BITS_PER_WIDE_INT - 1))
+      && (this->len == len))
+    end = prec;
+  else
+    end = this->len * HOST_BITS_PER_WIDE_INT;
+
+  for (s = 0; s < end; s += 8)
+    {
+      unsigned int d = prec - s - 8;
+      unsigned HOST_WIDE_INT byte;
+
+      int block = s / HOST_BITS_PER_WIDE_INT;
+      int offset = s & (HOST_BITS_PER_WIDE_INT - 1);
+
+      byte = (val[block] >> offset) & 0xff;
+
+      block = d / HOST_BITS_PER_WIDE_INT;
+      offset = d & (HOST_BITS_PER_WIDE_INT - 1);
+
+      result.val[block] &= ((((HOST_WIDE_INT)1 << offset) + 8)
+			    - ((HOST_WIDE_INT)1 << offset));
+      result.val[block] |= byte << offset;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int::bswap", result, *this);
+#endif
+
+  return result;
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  */
+
+wide_int
+wide_int::mask (int width, bool negate, enum machine_mode mode)
+{
+  wide_int result;
+  int i = 0;
+  int shift;
+
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int_minus_one (mode);
+      else
+	result = wide_int_zero (mode);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wvv ("wide_int::mask", result, width, negate);
+#endif
+      return result;
+    }
+
+  result.mode = mode;
+
+  while (i < width / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = width & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      HOST_WIDE_INT last = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~last : last;
+    }
+  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvv ("wide_int::mask", result, width, negate);
+#endif
+
+  return result;
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  */
+
+wide_int
+wide_int::shifted_mask (int start, int width, bool negate,
+			enum machine_mode mode)
+{
+  wide_int result;
+  int i = 0;
+  int shift;
+  int end = start + width;
+  HOST_WIDE_INT block;
+  int prec = GET_MODE_PRECISION (mode);
+
+  if (start + width > prec)
+    {
+      width = prec - start;
+      if (width < 0)
+	{
+	  width = 0;
+	  start = prec;
+	}
+    }
+
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int_minus_one (mode);
+      else
+	result = wide_int_zero (mode);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wvv ("wide_int::shifted_mask", result, width, negate);
+#endif
+      return result;
+    }
+
+  result.mode = mode;
+
+  while (i < start / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? (HOST_WIDE_INT)-1 : 0;
+
+  shift = start & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift)
+    {
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      shift = (end) & (HOST_BITS_PER_WIDE_INT - 1);
+      if (shift)
+	{
+	  /* case 000111000 */
+	  block = (((HOST_WIDE_INT)1) << shift) - block - 1;
+	  result.val[i++] = negate ? ~block : block;
+	  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_wvvv ("wide_int::shifted_mask", result, start,
+				  width, negate);
+#endif
+	  return result;
+	}
+      else
+	/* ...111000 */
+	result.val[i++] = negate ? block : ~block;
+    }
+
+  while (i < end / HOST_BITS_PER_WIDE_INT)
+    /* 1111111 */
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = end & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      /* 000011111 */
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~block : block;
+    }
+
+  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvvv ("wide_int::shifted_mask", result, start, width,
+			  negate);
+#endif
+
+  return result;
+}
+
+
+/*
+ * logical operations.
+ */
+
+/* Return THIS & OP1.  */
+
+wide_int
+wide_int::operator & (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  gcc_assert (mode == op1.mode);
+
+  result.len = len > op1.len ? len : op1.len;
+  result.mode = mode;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	  result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l0] = op1.val[l0];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator &", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Return THIS & ~OP1.  */
+
+wide_int
+wide_int::and_not (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  gcc_assert (mode == op1.mode);
+
+  result.len = len > op1.len ? len : op1.len;
+  result.mode = mode;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l0] = ~op1.val[l0];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & ~op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::and_not", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+wide_int
+wide_int::operator | (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  gcc_assert (mode == op1.mode);
+
+  result.len = len > op1.len ? len : op1.len;
+  result.mode = mode;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l0] = op1.val[l0];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator |", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Return the logical negation (bitwise complement) of THIS.  */
+
+wide_int
+wide_int::operator ~ () const
+{
+  wide_int result;
+  int l0 = len - 1;
+
+  result.len = len;
+  result.mode = mode;
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = ~val[l0];
+      l0--;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int::operator ~", result, *this);
+#endif
+  return result;
+}
+
+/* Return THIS | ~OP1.  */
+
+wide_int
+wide_int::or_not (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  gcc_assert (mode == op1.mode);
+
+  result.len = len > op1.len ? len : op1.len;
+  result.mode = mode;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l0] = ~op1.val[l0];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | ~op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::and_not", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Return the exclusive ior (xor) of THIS and OP1.  */
+
+wide_int
+wide_int::operator ^ (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  gcc_assert (mode == op1.mode);
+
+  result.len = len > op1.len ? len : op1.len;
+  result.mode = mode;
+
+  while (l0 > l1)
+    {
+      result.val[l0] = val[l0] ^ op1.sign_mask ();
+      l0--;
+    }
+
+  while (l1 > l0)
+    {
+      result.val[l0] = sign_mask () ^ op1.val[l0];
+      l1--;
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] ^ op1.val[l0];
+      l0--;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator ^", result, *this, op1);
+#endif
+  return result;
+}
+
+/*
+ * math
+ */
+
+/* Absolute value of THIS.  */
+
+wide_int
+wide_int::abs () const
+{
+  if (sign_mask ())
+    return neg ();
+
+  wide_int result = copy (mode);
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int::abs", result, *this);
+#endif
+  return result;
+}
+
+/* Add of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::operator + (const wide_int &op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int prec = precision ();
+  unsigned int i, small_prec, stop;
+
+  gcc_assert (mode == op1.mode);
+
+  result.mode = mode;
+
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      o1 = op1.val[0];
+      result.val[0] = sext (o0 + o1, prec);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator +", result, *this, op1);
+#endif
+      return result;
+    }
+
+  stop = len > op1.len ? len : op1.len;
+  /* Need to do one extra block just to handle the special cases.  */
+  if (stop < (unsigned)BLOCKS_NEEDED (prec))
+    stop++;
+
+  result.len = stop;
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < stop; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1.len ? (unsigned HOST_WIDE_INT)op1.val[i] : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (prec) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator +", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Add of THIS and signed OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::operator + (HOST_WIDE_INT op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int prec = precision ();
+  unsigned int i, small_prec, stop;
+
+  result.mode = mode;
+
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      result.val[0] = sext (o0 + op1, prec);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::add", result, *this, op1);
+#endif
+      return result;
+    }
+
+  stop = len;
+  /* Need to do one extra block just to handle the special cases.  */
+  if (stop < (unsigned)BLOCKS_NEEDED (prec))
+    stop++;
+
+  result.len = stop;
+  mask0 = sign_mask ();
+  mask1 = op1 >> (HOST_BITS_PER_WIDE_INT - 1);
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < 1 ? (unsigned HOST_WIDE_INT)op1 : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (prec) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator +", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Add of THIS and unsigned OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::operator + (unsigned HOST_WIDE_INT op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0;
+  int prec = precision ();
+  unsigned int i, small_prec, stop;
+
+  result.mode = mode;
+
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      result.val[0] = sext (o0 + op1, prec);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator +", result, *this, op1);
+#endif
+      return result;
+    }
+
+  stop = len;
+  /* Need to do one extra block just to handle the special cases.  */
+  if (stop < (unsigned)BLOCKS_NEEDED (prec))
+    stop++;
+
+  result.len = stop;
+  mask0 = sign_mask ();
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < stop; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < 1 ? (unsigned HOST_WIDE_INT)op1 : 0;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (prec) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator +", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Add of OP0 and OP1 with overflow checking.  If the result overflows
+   within the precision, set OVERFLOW.  OVERFLOW is assumed to be
+   sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::add_overflow (const wide_int *op0, const wide_int *op1,
+			wide_int::Op sgn, bool *overflow)
+{
+  wide_int result;
+  const wide_int *tmp;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  int prec = op0->precision ();
+  int i, small_prec;
+
+  gcc_assert (op0->get_mode () == op1->get_mode ());
+
+  result.set_mode (op0->get_mode ());
+
+  /* Put the longer one first.  */
+  if (op0->get_len () > op1->get_len ())
+    {
+      tmp = op0;
+      op0 = op1;
+      op1 = tmp;
+    }
+
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < op0->get_len (); i++)
+    {
+      o0 = op0->elt (i);
+      o1 = op1->elt (i);
+      x = o0 + o1 + carry;
+      result.elt_ref (i) = x;
+      carry = x < o0;
+    }
+
+  /* Uncompress the rest.  */
+  if (op0->get_len () < op1->get_len ())
+    {
+      unsigned HOST_WIDE_INT mask = op1->sign_mask ();
+      for (i = op0->get_len (); i < op1->get_len (); i++)
+	{
+	  o0 = op0->elt (i);
+	  o1 = mask;
+	  x = o0 + o1 + carry;
+	  result.elt_ref (i) = x;
+	  carry = x < o0;
+	}
+    }
+
+  result.set_len (op0->get_len ());
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (op0->get_len () * HOST_BITS_PER_WIDE_INT < prec)
+	{
+	  /* If the carry is 1, then we need another word.  If the carry
+	     is 0, we only need another word if the top bit is 1.  */
+	  if (carry == 1
+	      || (x >> (HOST_BITS_PER_WIDE_INT - 1) == 1))
+	    /* Check for signed overflow.  */
+	    {
+	      result.elt_ref (result.get_len ()) = carry;
+	      result.set_len (result.get_len () + 1);
+	    }
+	  if (sgn == wide_int::SIGNED)
+	    {
+	      if (((x ^ o0) & (x ^ o1)) >> (HOST_BITS_PER_WIDE_INT - 1))
+		*overflow = true;
+	    }
+	  else if (carry)
+	    {
+	      if ((~o0) < o1)
+		*overflow = true;
+	    }
+	  else
+	    {
+	      if ((~o0) <= o1)
+		*overflow = true;
+	    }
+	}
+    }
+  else
+    {
+      /* Overflow in this case is easy since we can see bits beyond
+	 the precision.  If the value computed is not the sign
+	 extended value, then we have overflow.  */
+      unsigned HOST_WIDE_INT y;
+
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  Then the rest of the code just works.  */
+	  o0 = wide_int::zext (o0, small_prec);
+	  o1 = wide_int::zext (o1, small_prec);
+	  x = o0 + o1 + carry;
+	}
+      /* Short integers and modes with weird precisions.  */
+      y = wide_int::sext (x, small_prec);
+      result.set_len (op1->get_len ());
+      if (BLOCKS_NEEDED (prec) == result.get_len () && x != y)
+	*overflow = true;
+      /* Then put the sign extended form back because that is the
+	 canonical form.  */
+      result.elt_ref (result.get_len () - 1) = y;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::add_overflow", result, *op0, *op1);
+#endif
+  return result;
+}
+
+/* Add this and X.  If overflow occurs, set OVERFLOW.  */
+
+wide_int
+wide_int::add (const wide_int &x, Op sgn, bool *overflow) const
+{
+  return add_overflow (this, &x, sgn, overflow);
+}
+
+/* Count leading zeros of THIS but only looking at the bits in the
+   smallest HWI of size mode.  */
+
+wide_int
+wide_int::clz (enum machine_mode m) const
+{
+  return wide_int::from_shwi (clz (), m);
+}
+
+/* Count leading zeros of THIS.  */
+
+HOST_WIDE_INT
+wide_int::clz () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int prec = precision ();
+  int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+
+  if (zero_p ())
+    {
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = prec;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_vw ("wide_int::clz", count, *this);
+#endif
+      return count;
+    }
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (prec) == len && small_prec)
+    {
+      v = zext (val[len - 1], small_prec);
+      count = clz_hwi (v) - (HOST_BITS_PER_WIDE_INT - small_prec);
+      start = len - 2;
+      if (v != 0)
+	{
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_vw ("wide_int::clz", count, *this);
+#endif
+	  return count;
+	}
+    }
+  else
+    {
+      count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (prec) - len);
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = elt (i);
+      count += clz_hwi (v);
+      if (v != 0)
+	break;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int::clz", count, *this);
+#endif
+  return count;
+}
+
+wide_int
+wide_int::clrsb (enum machine_mode m) const
+{
+  return wide_int::from_shwi (clrsb (), m);
+}
+
+/* Count the number of redundant leading bits of THIS.  Return result
+   as a HOST_WIDE_INT.  There is a wrapper to convert this into a
+   wide_int.  */
+
+HOST_WIDE_INT
+wide_int::clrsb () const
+{
+  if (neg_p ())
+    return operator ~ ().clz () - 1;
+
+  return clz () - 1;
+}
+
+wide_int
+wide_int::ctz (enum machine_mode mode) const
+{
+  return wide_int::from_shwi (ctz (), mode);
+}
+
+/* Count zeros of THIS.  Return result as a HOST_WIDE_INT.  There is a
+   wrapper to convert this into a wide_int.  */
+
+HOST_WIDE_INT
+wide_int::ctz () const
+{
+  int i;
+  int count = 0;
+  HOST_WIDE_INT v;
+  int prec = precision ();
+  int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  int end;
+  bool more_to_do;
+
+  if (zero_p ())
+    {
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = prec;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_vw ("wide_int::ctz", count, *this);
+#endif
+      return count;
+    }
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (prec) == len && small_prec)
+    {
+      end = len - 1;
+      more_to_do = true;
+    }
+  else
+    {
+      end = len;
+      more_to_do = false;
+    }
+
+  for (i = 0; i < end; i++)
+    {
+      v = val[i];
+      count += ctz_hwi (v);
+      if (v != 0)
+	{
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_vw ("wide_int::ctz", count, *this);
+#endif
+	  return count;
+	}
+    }
+
+  if (more_to_do)
+    {
+      v = zext (val[len - 1], small_prec);
+      count = ctz_hwi (v);
+      /* The top word was all zeros so we have to cut it back to prec,
+	 because we are counting some of the zeros above the
+	 interesting part.  */
+      if (count > prec)
+	count = prec;
+    }
+  else
+    /* Skip over the blocks that are not represented.  They must be
+       all zeros at this point.  */
+    count = prec;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int::ctz", count, *this);
+#endif
+  return count;
+}
+
+/* ffs of THIS.  */
+
+wide_int
+wide_int::ffs () const
+{
+  int prec = precision ();
+  HOST_WIDE_INT count = ctz ();
+  if (count == prec)
+    count = 0;
+  else
+    count += 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int::ffs", count, *this);
+#endif
+  return wide_int::from_shwi (count, word_mode);
+}
+
+/* Subroutines of the multiplication and division operations.  Unpack
+   the first IN_LEN HOST_WIDE_INTs in INPUT into 2 * IN_LEN
+   HOST_HALF_WID_INTs of RESULT.  The rest of RESULT is filled by
+   uncompressing the top bit of INPUT[IN_LEN - 1].  */
+
+static void
+wi_unpack (unsigned HOST_HALF_WIDE_INT *result, 
+	   const unsigned HOST_WIDE_INT *input,
+	   int in_len, int out_len)
+{
+  int i;
+  int j = 0;
+  HOST_WIDE_INT mask;
+
+  for (i = 0; i <in_len; i++)
+    {
+      result[j++] = input[i];
+      result[j++] = input[i] >> HOST_BITS_PER_HALF_WIDE_INT;
+    }
+  mask = ((HOST_WIDE_INT)input[in_len - 1]) >> (HOST_BITS_PER_WIDE_INT - 1);
+  mask &= HALF_INT_MASK;
+
+  /* Smear the sign bit.  */
+  while (j < out_len)
+    result[j++] = mask;
+}
+
+/* The inverse of wi_unpack.  */
+
+static void
+wi_pack (unsigned HOST_WIDE_INT *result, 
+	 const unsigned HOST_HALF_WIDE_INT *input, 
+	 int in_len)
+{
+  int i = 0;
+  int j = 0;
+
+  while (i < in_len)
+    {
+      result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+	| ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+      i += 2;
+    }
+}
+
+/* Return an integer that is the exact log2 of THIS.  */
+
+HOST_WIDE_INT
+wide_int::exact_log2 () const
+{
+  int prec = precision ();
+  int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  HOST_WIDE_INT count;
+  HOST_WIDE_INT result;
+
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec < HOST_BITS_PER_WIDE_INT)
+	v = sext (val[0], small_prec);
+      else
+	v = val[0];
+      result = ::exact_log2 (v);
+      goto ex;
+    }
+
+  count = ctz ();
+  if (clz () + count + 1 == prec)
+    {
+      result = count;
+      goto ex;
+    }
+
+  result = -1;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int::exact_log2", result, *this);
+#endif
+  return result;
+}
+
+/* Multiply THIS and OP1.  If HIGH is set, only the upper half of the
+   result is returned.  If FULL is set, the entire result is returned
+   in a mode that is twice the width of the inputs.  However, that
+   mode needs to exist if the value is to be usable.  Clients that use
+   FULL need to check for this.
+
+   If HIGH or FULL are not setm throw away the upper half after the check
+   is made to see if it overflows.  Unfortunately there is no better
+   way to check for overflow than to do this.  OVERFLOW is assumed to
+   be sticky so it should be initialized.  SGN controls the signess
+   and is used to check overflow or if HIGH or FULL is set.  */
+
+wide_int
+wide_int::mul_internal (bool high, bool full, 
+			const wide_int *op1, const wide_int *op2,
+			wide_int::Op sgn,  bool *overflow, bool needs_overflow)
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1, k, t;
+  unsigned int i;
+  unsigned int j;
+  int prec = op1->precision ();
+  unsigned int blocks_needed = 2 * BLOCKS_NEEDED (prec);
+  unsigned HOST_HALF_WIDE_INT u[2 * MAX_BITSIZE_MODE_ANY_INT
+			   / HOST_BITS_PER_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT v[2 * MAX_BITSIZE_MODE_ANY_INT
+			   / HOST_BITS_PER_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT r[4 * MAX_BITSIZE_MODE_ANY_INT
+			   / HOST_BITS_PER_WIDE_INT];
+  HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT / 2)) - 1;
+
+  gcc_assert (op1->get_mode () == op2->get_mode ());
+  result.set_mode (op1->get_mode ());
+
+  if (high || full || needs_overflow)
+    {
+      /* If we need to check for overflow, we can only do half wide
+	 multiplies quickly because we need to look at the top bits to
+	 check for the overflow.  */
+      if (prec <= HOST_BITS_PER_HALF_WIDE_INT)
+	{
+	  HOST_WIDE_INT t;
+	  result.set_len (1);
+	  o0 = op1->elt (0);
+	  o1 = op2->elt (0);
+	  t = o0 * o1;
+	  /* Signed shift down will leave 0 or -1 if there was no
+	     overflow for signed or 0 for unsigned.  */
+	  t = t >> (HOST_BITS_PER_HALF_WIDE_INT - 1);
+	  if (needs_overflow)
+	    {
+	      if (sgn == wide_int::SIGNED)
+		{
+		  if (t != (HOST_WIDE_INT)-1 && t != 0)
+		    *overflow = true;
+		}
+	      else
+		{
+		  if (t != 0)
+		    *overflow = true;
+		}
+	    }
+	  if (full)
+	    {
+	      result.elt_ref (0) = wide_int::sext (t, prec << 1);
+	      result.set_mode (GET_MODE_2XWIDER_MODE (op1->get_mode ()));
+	    }
+	  else if (high)
+	    result.elt_ref (0) = wide_int::sext (t >> (prec >> 1), prec);
+	  else
+	    result.elt_ref (0) = wide_int::sext (t, prec);
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_www ("wide_int::mul_overflow", result, *op1, *op2);
+#endif
+	  return result;
+	}
+    }
+  else
+    {
+      if (prec <= HOST_BITS_PER_WIDE_INT)
+	{
+	  result.set_len (1);
+	  o0 = op1->elt (0);
+	  o1 = op2->elt (0);
+	  result.elt_ref (0) = wide_int::sext (o0 * o1, prec);
+	  
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_www ("wide_int::mul_overflow", result, *op1, *op2);
+#endif
+	  return result;
+	}
+    }
+
+  wi_unpack (u, &op1->uelt_ref (0), op1->get_len (), blocks_needed);
+  wi_unpack (v, &op2->uelt_ref (0), op2->get_len (), blocks_needed);
+
+  memset (r, 0, blocks_needed * 2 * HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT);
+
+  for (j = 0; j < blocks_needed; j++)
+    {
+      k = 0;
+      for (i = 0; i < blocks_needed; i++)
+	{
+	  t = ((unsigned HOST_WIDE_INT)u[i] * (unsigned HOST_WIDE_INT)v[j]
+	       + r[i + j] + k);
+	  r[i + j] = t & HALF_INT_MASK;
+	  k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	}
+      r[j + blocks_needed] = k;
+    }
+
+  if (needs_overflow)
+    {
+      HOST_WIDE_INT top;
+
+      /* For unsigned, overflow is true if any of the top bits are set.
+	 For signed, overflow is true if any of the top bits are not equal
+	 to the sign bit.  */
+      if (sgn == wide_int::UNSIGNED)
+	top = 0;
+      else
+	{
+	  top = r[blocks_needed - 1];
+	  top = ((top << (HOST_BITS_PER_WIDE_INT / 2))
+		 >> (HOST_BITS_PER_WIDE_INT - 1));
+	  top &= mask;
+	}
+      
+      for (i = blocks_needed; i < 2 * blocks_needed; i++)
+	if (((HOST_WIDE_INT)(r[i] & mask)) != top)
+	  *overflow = true; 
+    }
+
+  if (full)
+    {
+      /* compute [2prec] <- [prec] * [prec] */
+      wi_pack (&result.uelt_ref (0), r, blocks_needed);
+      result.set_len (blocks_needed);
+      result.set_mode (GET_MODE_2XWIDER_MODE (op1->get_mode ()));
+    }
+  else if (high)
+    {
+      /* compute [prec] <- ([prec] * [prec]) >> [prec] */
+      wi_pack (&result.uelt_ref (blocks_needed >> 1), r, blocks_needed >> 1);
+      result.set_len (blocks_needed / 2);
+    }
+  else
+    {
+      /* compute [prec] <- ([prec] * [prec]) && ((1 << [prec]) - 1) */
+      wi_pack (&result.uelt_ref (0), r, blocks_needed >> 1);
+      result.set_len (blocks_needed / 2);
+    }
+      
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwwv ("wide_int::mul_overflow", result, *op1, *op2, *overflow);
+#endif
+  return result;
+}
+
+/* Multiply THIS and OP1.  The result is the same precision as the
+   operands, so there is no reason for signed or unsigned
+   versions.  */
+
+wide_int
+wide_int::operator * (const wide_int &op1) const
+{
+  bool overflow;
+
+  return mul_internal (false, false, this, &op1, UNSIGNED, &overflow, false);
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.
+   OVERFLOW is set true if the result overflows.  */
+
+wide_int 
+wide_int::mul (const wide_int &op1, Op sgn, bool *overflow) const
+{
+  return mul_internal (false, false, this, &op1, sgn, overflow, true);
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.  The
+   result is twice the precision as the operands.  NOTE THAT A MODE
+   MUST EXIST ON THE TARGET THAT IS TWICE THE WIDTH OF THE MODES OF
+   THE OPERANDS.  The signess is specified with SGN.  */
+
+wide_int
+wide_int::mul_full (const wide_int &op1, Op sgn) const
+{
+  bool overflow;
+
+  return mul_internal (false, true, this, &op1, sgn, &overflow, false);
+}
+
+/* Multiply THIS and OP1 and return the high part of that result.  The
+   signess is specified with SGN.  The result is the same precision as
+   the operands.  The mode is the same mode as the operands.  The
+   signess is specified with y.  */
+
+wide_int
+wide_int::mul_high (const wide_int &op1, Op sgn) const
+{
+  bool overflow;
+
+  return mul_internal (true, false, this, &op1, sgn, &overflow, false);
+}
+
+/* Negate THIS.  */
+
+wide_int
+wide_int::neg () const
+{
+  wide_int z = wide_int::from_shwi (0, mode);
+  return z - *this;
+}
+
+static inline wide_int
+parity (const wide_int &x)
+{
+  return x.parity (x.get_mode ());
+}
+
+/* Compute the parity of THIS.  */
+
+wide_int
+wide_int::parity (enum machine_mode mode) const
+{
+  int count = popcount ();
+  return wide_int::from_shwi (count & 1, mode);
+}
+
+static inline int
+popcount (const wide_int &x)
+{
+  return x.popcount ();
+}
+
+wide_int
+wide_int::popcount (enum machine_mode m) const
+{
+  return wide_int::from_shwi (popcount (), m);
+}
+
+/* Compute the population count of THIS.  */
+
+int
+wide_int::popcount () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int prec = precision ();
+  int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (prec) == len && small_prec)
+    {
+      v = zext (val[len - 1], small_prec);
+      count = popcount_hwi (v);
+      start = len - 2;
+    }
+  else
+    {
+      if (sign_mask ())
+	count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (prec) - len);
+      else
+	count = 0;
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = val[i];
+      count += popcount_hwi (v);
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int::popcount", count, *this);
+#endif
+  return count;
+}
+
+/* Subtract of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::operator - (const wide_int &op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the carry in of the first element at 1.  */
+  unsigned HOST_WIDE_INT carry = 1;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int prec = precision ();
+  unsigned int i, small_prec, stop;
+
+  gcc_assert (mode == op1.mode);
+
+  result.mode = mode;
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      o1 = op1.val[0];
+      result.val[0] = sext (o0 - o1, prec);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator -", result, *this, op1);
+#endif
+      return result;
+    }
+
+  stop = len > op1.len ? len : op1.len;
+  /* Need to do one extra block just to handle the special cases.  */
+  if (stop < (unsigned)BLOCKS_NEEDED (prec))
+    stop++;
+
+  result.len = stop;
+  mask0 = sign_mask ();
+  mask1 = ~op1.sign_mask ();
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < stop; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1.len ? (unsigned HOST_WIDE_INT)~op1.val[i] : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (prec) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator -", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Subtract of signed OP1 from THIS.  No overflow is detected.  */
+
+wide_int
+wide_int::operator - (HOST_WIDE_INT op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the carry in of the first element at 1.  */
+  unsigned HOST_WIDE_INT carry = 1;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int prec = precision ();
+  unsigned int i, small_prec, stop;
+
+  result.mode = mode;
+
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      result.val[0] = sext (o0 - op1, prec);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator -", result, *this, op1);
+#endif
+      return result;
+    }
+
+  stop = len;
+  /* Need to do one extra block just to handle the special cases.  */
+  if (stop < (unsigned)BLOCKS_NEEDED (prec))
+    stop++;
+
+  result.len = stop;
+  mask0 = sign_mask ();
+  mask1 = ~(op1 >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < stop; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < 1 ? (unsigned HOST_WIDE_INT)~op1 : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (prec) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator -", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Subtract of unsigned OP1 from THIS.  No overflow is detected.  */
+
+wide_int
+wide_int::operator - (unsigned HOST_WIDE_INT op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the carry in of the first element at 1.  */
+  unsigned HOST_WIDE_INT carry = 1;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int prec = precision ();
+  unsigned int i, small_prec, stop;
+
+  result.mode = mode;
+
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      result.val[0] = sext (o0 - op1, prec);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator -", result, *this, op1);
+#endif
+      return result;
+    }
+
+  stop = len;
+  /* Need to do one extra block just to handle the special cases.  */
+  if (stop < (unsigned)BLOCKS_NEEDED (prec))
+    stop++;
+
+  result.len = stop;
+  mask0 = sign_mask ();
+  mask1 = (HOST_WIDE_INT) -1;
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < stop; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < 1 ? (unsigned HOST_WIDE_INT)~op1 : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (prec) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator -", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Subtract of THIS and OP1 with overflow checking.  If the result
+   overflows within the precision, set OVERFLOW.  OVERFLOW is assumed
+   to be sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::sub_overflow (const wide_int *op0, const wide_int *op1, 
+			wide_int::Op sgn, bool *overflow)
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the carry in of the first element at 1.  */
+  unsigned HOST_WIDE_INT carry = 1;
+  int prec = op1->precision ();
+  int i, small_prec;
+
+  gcc_assert (op0->get_mode () == op1->get_mode ());
+
+  result.set_mode (op0->get_mode ());
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < op0->get_len (); i++)
+    {
+      o0 = op0->elt (i);
+      o1 = ~op1->elt (i);
+      x = o0 + o1 + carry;
+      result.elt_ref (i) = x;
+      carry = x < o0;
+    }
+
+  /* Uncompress the rest.  */
+  if (op1->get_len () < op1->get_len ())
+    {
+      unsigned HOST_WIDE_INT mask = op1->sign_mask ();
+      for (i = op0->get_len (); i < op1->get_len (); i++)
+	{
+	  o0 = op0->elt (i);
+	  o1 = ~mask;
+	  x = o0 + o1 + carry;
+	  result.elt_ref (i) = x;
+	  carry = x < o0;
+	}
+    }
+  else if (op0->get_len () > op1->get_len ())
+    {
+      unsigned HOST_WIDE_INT mask = op1->sign_mask ();
+      for (i = op0->get_len (); i < op1->get_len (); i++)
+	{
+	  o0 = mask;
+	  o1 = ~op1->elt (i);
+	  x = o0 + o1 + carry;
+	  result.elt_ref (i) = x;
+	  carry = x < o0;
+	}
+    }
+
+  result.set_len (op0->get_len ());
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (op0->get_len () * HOST_BITS_PER_WIDE_INT < prec)
+	{
+	  /* If the carry is 1, then we need another word.  If the carry
+	     is 0, we only need another word if the top bit is 1.  */
+	  if (carry == 1
+	      || (x >> (HOST_BITS_PER_WIDE_INT - 1) == 1))
+	    {
+	      /* Check for signed overflow.  */
+	      result.elt_ref (result.get_len ()) = carry;
+	      result.set_len (result.get_len () + 1);
+	    }
+	  if (sgn == wide_int::SIGNED)
+	    {
+	      if (((x ^ o0) & (x ^ o1)) >> (HOST_BITS_PER_WIDE_INT - 1))
+		*overflow = true;
+	    }
+	  else if (carry)
+	    {
+	      if ((~o0) < o1)
+		*overflow = true;
+	    }
+	  else
+	    {
+	      if ((~o0) <= o1)
+		*overflow = true;
+	    }
+	}
+    }
+  else
+    {
+      /* Overflow in this case is easy since we can see bits beyond
+	 the precision.  If the value computed is not the sign
+	 extended value, then we have overflow.  */
+      unsigned HOST_WIDE_INT y;
+
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  Then the rest of the code just works.  */
+	  o0 = wide_int::zext (o0, small_prec);
+	  o1 = wide_int::zext (o1, small_prec);
+	  x = o0 + o1 + carry;
+	}
+      /* Short integers and modes with weird precisions.  */
+      y = wide_int::sext (x, small_prec);
+      result.set_len (op1->get_len ());
+      if (BLOCKS_NEEDED (prec) == result.get_len () && x != y)
+	*overflow = true;
+      /* Then put the sign extended form back because that is the
+	 canonical form.  */
+      result.elt_ref (result.get_len () - 1) = y;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::sub_overflow", result, *op0, *op1);
+#endif
+  return result;
+}
+
+/* sub X from THIS.  If overflow occurs, set OVERFLOW.  */
+
+wide_int
+wide_int::sub (const wide_int &x, Op sgn, bool *overflow) const
+{
+  return sub_overflow (this, &x, sgn, overflow);
+}
+
+/* Truncate THIS to MODE.  */
+
+wide_int
+wide_int::truncate (enum machine_mode m) const
+{
+  gcc_assert (GET_MODE_PRECISION (m) <= precision ());
+  return copy (m);
+}
+
+/*
+ * Division and Mod
+ */
+
+/* Compute B_QUOTIENT and B_REMAINDER from B_DIVIDEND/B_DIVISOR.  The
+   algorithm is a small modification of the algorithm in Hacker's
+   Delight by Warren, which itself is a small modification of Knuth's
+   algorithm.  M is the number of significant elements of U however
+   there needs to be at least one extra element of B_DIVIDEND
+   allocated, N is the number of elements of B_DIVISOR.  */
+
+static void
+divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+		   unsigned HOST_HALF_WIDE_INT *b_remainder,
+		   unsigned HOST_HALF_WIDE_INT *b_dividend, 
+		   unsigned HOST_HALF_WIDE_INT *b_divisor, 
+		   int m, int n)
+{
+  /* The "digits" are a HOST_HALF_WIDE_INT which the size of half of a
+     HOST_WIDE_INT and stored in the lower bits of each word.  This
+     algorithm should work properly on both 32 and 64 bit
+     machines.  */
+  unsigned HOST_WIDE_INT b
+    = (unsigned HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT;
+  unsigned HOST_WIDE_INT qhat;   /* Estimate of quotient digit.  */
+  unsigned HOST_WIDE_INT rhat;   /* A remainder.  */
+  unsigned HOST_WIDE_INT p;      /* Product of two digits.  */
+  HOST_WIDE_INT s, i, j, t, k;
+
+  /* Single digit divisor.  */
+  if (n == 1)
+    {
+      k = 0;
+      for (j = m - 1; j >= 0; j--)
+	{
+	  b_quotient[j] = (k * b + b_dividend[j])/b_divisor[0];
+	  k = ((k * b + b_dividend[j])
+	       - ((unsigned HOST_WIDE_INT)b_quotient[j]
+		  * (unsigned HOST_WIDE_INT)b_divisor[0]));
+	}
+      b_remainder[0] = k;
+      return;
+    }
+
+  s = clz_hwi (b_divisor[n-1]) - HOST_BITS_PER_HALF_WIDE_INT; /* CHECK clz */
+
+  /* Normalize B_DIVIDEND and B_DIVISOR.  Unlike the published
+     algorithm, we can overwrite b_dividend and b_divisor, so we do
+     that.  */
+  for (i = n - 1; i > 0; i--)
+    b_divisor[i] = (b_divisor[i] << s)
+      | (b_divisor[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_divisor[0] = b_divisor[0] << s;
+
+  b_dividend[m] = b_dividend[m-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s);
+  for (i = m - 1; i > 0; i--)
+    b_dividend[i] = (b_dividend[i] << s)
+      | (b_dividend[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_dividend[0] = b_dividend[0] << s;
+
+  /* Main loop.  */
+  for (j = m - n; j >= 0; j--)
+    {
+      qhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) / b_divisor[n-1];
+      rhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) - qhat * b_divisor[n-1];
+    again:
+      if (qhat >= b || qhat * b_divisor[n-2] > b * rhat + b_dividend[j+n-2])
+	{
+	  qhat -= 1;
+	  rhat += b_divisor[n-1];
+	  if (rhat < b)
+	    goto again;
+	}
+
+      /* Multiply and subtract.  */
+      k = 0;
+      for (i = 0; i < n; i++)
+	{
+	  p = qhat * b_divisor[i];
+	  t = b_dividend[i+j] - k - (p & HALF_INT_MASK);
+	  b_dividend[i + j] = t;
+	  k = ((p >> HOST_BITS_PER_HALF_WIDE_INT)
+	       - (t >> HOST_BITS_PER_HALF_WIDE_INT));
+	}
+      t = b_dividend[j+n] - k;
+      b_dividend[j+n] = t;
+
+      b_quotient[j] = qhat;
+      if (t < 0)
+	{
+	  b_quotient[j] -= 1;
+	  k = 0;
+	  for (i = 0; i < n; i++)
+	    {
+	      t = (HOST_WIDE_INT)b_dividend[i+j] + b_divisor[i] + k;
+	      b_dividend[i+j] = t;
+	      k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	    }
+	  b_dividend[j+n] += k;
+	}
+    }
+  for (i = 0; i < n; i++)
+    b_remainder[i] = (b_dividend[i] >> s) 
+      | (b_dividend[i+1] << (HOST_BITS_PER_HALF_WIDE_INT - s));
+}
+
+
+/* Do a truncating divide DIVISOR into DIVIDEND.  The result is the
+   same size as the operands.  SIGN is either wide_int::SIGNED or
+   wide_int::UNSIGNED.  */
+
+static wide_int
+divmod_internal (bool compute_quotient, 
+		 const wide_int *dividend, const wide_int *divisor,
+		 wide_int::Op sgn, wide_int *remainder, bool compute_remainder, 
+		 bool *overflow)
+{
+  wide_int quotient, u0, u1;
+  int prec = dividend->precision ();
+  int blocks_needed = 2 * BLOCKS_NEEDED (prec);
+  unsigned HOST_HALF_WIDE_INT b_quotient[2 * MAX_BITSIZE_MODE_ANY_INT
+				/ HOST_BITS_PER_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT b_remainder[2 * MAX_BITSIZE_MODE_ANY_INT
+				/ HOST_BITS_PER_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT b_dividend[(2 * MAX_BITSIZE_MODE_ANY_INT
+				 / HOST_BITS_PER_WIDE_INT) + 1];
+  unsigned HOST_HALF_WIDE_INT b_divisor[2 * MAX_BITSIZE_MODE_ANY_INT
+				/ HOST_BITS_PER_WIDE_INT];
+  int m, n;
+  bool dividend_neg = false;
+  bool divisor_neg = false;
+
+  if ((*divisor).zero_p ())
+    *overflow = true;
+
+  /* The smallest signed number / -1 causes overflow.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      wide_int t = wide_int::set_bit_in_zero ((*dividend).precision () - 1, 
+					      (*dividend).get_mode ());
+      if (*dividend == t && (*divisor).minus_one_p ())
+	*overflow = true;
+    }
+
+  gcc_assert (dividend->get_mode () == divisor->get_mode ());
+  quotient.set_mode (dividend->get_mode ());
+  remainder->set_mode (dividend->get_mode ());
+
+  /* If overflow is set, just get out.  There will only be grief by
+     continuing.  */
+  if (*overflow)
+    {
+      if (compute_remainder)
+	{
+	  remainder->set_len (1);
+	  remainder->elt_ref (0) = 0;
+	}
+      return wide_int_zero (quotient.get_mode ());
+    }
+
+  /* Do it on the host if you can.  */
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      quotient.set_len (1);
+      remainder->set_len (1);
+      if (sgn == wide_int::SIGNED)
+	{
+	  quotient.elt_ref (0) = wide_int::sext (dividend->elt (0) / divisor->elt (0), prec);
+	  remainder->elt_ref (0) = wide_int::sext (dividend->elt (0) % divisor->elt (0), prec);
+	}
+      else
+	{
+	  unsigned HOST_WIDE_INT o0 = dividend->elt (0);
+	  unsigned HOST_WIDE_INT o1 = divisor->elt (0);
+
+	  if (prec < HOST_BITS_PER_WIDE_INT)
+	    {
+	      o0 = wide_int::zext (o0, prec);
+	      o1 = wide_int::zext (o1, prec);
+	    }
+	  quotient.elt_ref (0) = wide_int::sext (o0 / o1, prec);
+	  remainder->elt_ref (0) = wide_int::sext (o0 % o1, prec);
+	}
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwww ("wide_int::divmod", quotient, *remainder, *dividend, *divisor);
+#endif
+      return quotient;
+    }
+
+  /* Make the divisor and divident positive and remember what we
+     did.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      if (dividend->sign_mask ())
+	{
+	  u0 = dividend->neg ();
+	  dividend = &u0;
+	  dividend_neg = true;
+	}
+      if (divisor->sign_mask ())
+	{
+	  u1 = divisor->neg ();
+	  divisor = &u1;
+	  divisor_neg = true;
+	}
+    }
+
+  wi_unpack (b_dividend, &dividend->uelt_ref (0), dividend->get_len (),
+	     blocks_needed);
+  wi_unpack (b_divisor, &divisor->uelt_ref (0), divisor->get_len (),
+	     blocks_needed);
+
+  if (dividend->sign_mask ())
+    m = blocks_needed;
+  else
+    m = 2 * dividend->get_len ();
+
+  if (divisor->sign_mask ())
+    n = blocks_needed;
+  else
+    n = 2 * divisor->get_len ();
+
+  divmod_internal_2 (b_quotient, b_remainder, b_dividend, b_divisor, m, n);
+
+  if (compute_quotient)
+    {
+      wi_pack (&quotient.uelt_ref (0), b_quotient, m);
+      quotient.set_len (m / 2);
+      quotient.canonize ();
+      /* The quotient is neg if exactly one of the divisor or dividend is
+	 neg.  */
+      if (dividend_neg != divisor_neg)
+	quotient = quotient.neg ();
+    }
+
+  if (compute_remainder)
+    {
+      wi_pack (&remainder->uelt_ref (0), b_remainder, n);
+      remainder->set_len (n / 2);
+      (*remainder).canonize ();
+      /* The remainder is always the same sign as the dividend.  */
+      if (dividend_neg)
+	*remainder = (*remainder).neg ();
+    }
+
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwww ("wide_int::divmod", quotient, *remainder, *dividend, *divisor);
+#endif
+  return quotient;
+}
+
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is
+   truncated.  */
+
+wide_int
+wide_int::div_trunc (const wide_int &divisor, Op sgn) const
+{
+  wide_int remainder;
+  bool overflow;
+
+  return divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, false, &overflow);
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is truncated.
+   Overflow is set to true if the result overflows, otherwise it is
+   not set.  */
+wide_int
+wide_int::div_trunc (const wide_int &divisor, Op sgn, bool *overflow) const
+{
+  wide_int remainder;
+  
+  return divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, false, overflow);
+}
+
+/* Divide DIVISOR into THIS producing both the quotient and remainder.
+   The result is the same size as the operands.  The sign is specified
+   in SGN.  The output is truncated.  */
+
+wide_int
+wide_int::divmod_trunc (const wide_int &divisor, wide_int *remainder, Op sgn) const
+{
+  bool overflow;
+
+  return divmod_internal (true, this, &divisor, sgn, 
+			  remainder, true, &overflow);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  */
+
+wide_int
+wide_int::mod_trunc (const wide_int &divisor, Op sgn) const
+{
+  bool overflow;
+  wide_int remainder;
+
+  divmod_internal (false, this, &divisor, sgn, 
+		   &remainder, true, &overflow);
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_trunc (const wide_int &divisor, Op sgn, bool *overflow) const
+{
+  wide_int remainder;
+
+  divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, true, overflow);
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is floor
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_floor (const wide_int &divisor, Op sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return quotient - (HOST_WIDE_INT)1;
+  return quotient;
+}
+
+
+/* Divide DIVISOR into THIS.  The remainder is also produced in
+   REMAINDER.  The result is the same size as the operands.  The sign
+   is specified in SGN.  The output is floor truncated.  Overflow is
+   set to true if the result overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::divmod_floor (const wide_int &divisor, wide_int *remainder, Op sgn) const
+{
+  wide_int quotient;
+  bool overflow;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      remainder, true, &overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !(*remainder).zero_p ())
+    {
+      *remainder = *remainder - divisor;
+      return quotient - (HOST_WIDE_INT)1;
+    }
+  return quotient;
+}
+
+
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is floor truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_floor (const wide_int &divisor, Op sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return remainder - divisor;
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is ceil
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_ceil (const wide_int &divisor, Op sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return quotient;
+      else
+	return quotient + (HOST_WIDE_INT)1;
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is the
+   same size as the operands.  The sign is specified in SGN.  The
+   output is ceil truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_ceil (const wide_int &divisor, Op sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return remainder;
+      else
+	return remainder - divisor;
+    }
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is round
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_round (const wide_int &divisor, Op sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+  if (!remainder.zero_p ())
+    {
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return quotient - (HOST_WIDE_INT)1;
+	      else 
+		return quotient + (HOST_WIDE_INT)1;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return quotient + (unsigned HOST_WIDE_INT)1;
+	}
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is round truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_round (const wide_int &divisor, Op sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return remainder + divisor;
+	      else 
+		return remainder - divisor;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return remainder - divisor;
+	}
+    }
+  return remainder;
+}
+
+/*
+ * Shifting, rotating and extraction.
+ */
+
+/* If SHIFT_COUNT_TRUNCATED is defined, truncate CNT.   
+
+   At first look, the shift truncation code does not look right.
+   Shifts (and rotates) are done according to the precision of the
+   mode but the shift count is truncated according to the bitsize
+   of the mode.   This is how real hardware works.
+
+   On an ideal machine, like Knuth's mix machine, a shift count is a
+   word long and all of the bits of that word are examined to compute
+   the shift amount.  But on real hardware, especially on machines
+   with fast (single cycle shifts) that takes too long.  On these
+   machines, the amount of time to perform a shift dictates the cycle
+   time of the machine so corners are cut to keep this fast.  A
+   comparison of an entire 64 bit word would take something like 6
+   gate delays before the shifting can even start.
+
+   So real hardware only looks at a small part of the shift amount.
+   On ibm machines, this tends to be 1 more than what is necessary to
+   encode the shift amount.  The rest of the world looks at only the
+   minimum number of bits.  This means that only 3 gate delays are
+   necessary to set up the shifter.
+
+   On the other hand, right shifts and rotates must be according to
+   the precision or the operation does not make any sense.   */
+static inline int
+trunc_shift (const enum machine_mode mode, int cnt)
+{
+#ifdef SHIFT_COUNT_TRUNCATED
+  cnt = cnt & (GET_MODE_BITSIZE (mode) - 1);
+#endif
+  return cnt;
+}
+
+/* This function is called in two contexts.  If OP == TRUNC, this
+   function provides a count that matches the semantics of the target
+   machine depending on the value of SHIFT_COUNT_TRUNCATED.  Note that
+   if SHIFT_COUNT_TRUNCATED is not defined, this function may produce
+   -1 as a value if the shift amount is greater than the bitsize of
+   the mode.  -1 is a surrogate for a very large amount.
+
+   If OP == NONE, then this function always truncates the shift value
+   to the bitsize because this shifting operation is a function that
+   is internal to GCC.  */
+
+static inline int
+trunc_shift (const enum machine_mode mode, const wide_int *cnt, wide_int::Op z)
+{
+  int bitsize = GET_MODE_BITSIZE (mode);
+
+  if (z == wide_int::TRUNC)
+    {
+#ifdef SHIFT_COUNT_TRUNCATED
+      return cnt->elt (0) & (bitsize - 1);
+#else
+      if (cnt.ltu (bitsize))
+	return cnt->elt (0) & (bitsize - 1);
+      else 
+	return -1;
+#endif
+    }
+  else
+    return cnt->elt (0) & (bitsize - 1);
+}
+
+/* Extract WIDTH bits from THIS starting at OFFSET.  The result is
+   assumed to fit in a HOST_WIDE_INT.  This function is safe in that
+   it can properly access elements that may not be explicitly
+   represented.  */
+
+HOST_WIDE_INT
+wide_int::extract_to_hwi (int offset, int width) const
+{
+  int start_elt, end_elt, shift;
+  HOST_WIDE_INT x;
+
+  /* Get rid of the easy cases first.   */
+  if (offset >= len * HOST_BITS_PER_WIDE_INT)
+    return sign_mask ();
+  if (offset + width <= 0)
+    return 0;
+
+  shift = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset < 0)
+    {
+      start_elt = -1;
+      end_elt = 0;
+      x = 0;
+    }
+  else
+    {
+      start_elt = offset / HOST_BITS_PER_WIDE_INT;
+      end_elt = (offset + width - 1) / HOST_BITS_PER_WIDE_INT;
+      x = start_elt >= len ? sign_mask () : val[start_elt] >> shift;
+    }
+
+  if (start_elt != end_elt)
+    {
+      HOST_WIDE_INT y = end_elt == len
+	? sign_mask () : val[end_elt];
+
+      x = (unsigned HOST_WIDE_INT)x >> shift;
+      x |= y << (HOST_BITS_PER_WIDE_INT - shift);
+    }
+
+  if (width != HOST_BITS_PER_WIDE_INT)
+    x &= ((HOST_WIDE_INT)1 << width) - 1;
+
+  return x;
+}
+
+
+/* Left shift by an integer Y.  See the definition of Op.TRUNC for how
+   to set Z.  */
+
+wide_int
+wide_int::lshift (int y, Op z) const
+{
+  return lshift (y, z, mode);
+}
+
+/* Left shifting by an wide_int shift amount.  See the definition of
+   Op.TRUNC for how to set Z.  */
+
+wide_int
+wide_int::lshift (const wide_int &y, Op z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (mode, &y, TRUNC);
+      if (shift == -1)
+	return wide_int_zero (mode);
+      return lshift (shift, NONE, mode);
+    }
+  else
+    return lshift (trunc_shift (mode, &y, NONE), NONE, mode);
+}
+
+/* Left shift THIS by CNT.  See the definition of Op.TRUNC for how to
+   set Z.  Since this is used internally, it has the ability to
+   specify the MODE independently.  This is useful when inserting a
+   small value into a larger one.  */
+
+wide_int
+wide_int::lshift (int cnt, Op op, enum machine_mode m) const
+{
+  wide_int result;
+  int res_prec = GET_MODE_PRECISION (m);
+  int i;
+
+  result.mode = m;
+
+  if (op == TRUNC)
+    cnt = trunc_shift (mode, cnt);
+
+  /* Handle the simple case quickly.   */
+  if (res_prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[0] = val[0] << cnt;
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::lshift", result, *this, cnt);
+#endif
+
+      return result;
+    }
+
+  if (cnt >= res_prec)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::lshift", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  for (i = 0; i < res_prec; i += HOST_BITS_PER_WIDE_INT)
+    result.val[i / HOST_BITS_PER_WIDE_INT]
+      = extract_to_hwi (i - cnt, HOST_BITS_PER_WIDE_INT);
+
+  result.len = BLOCKS_NEEDED (res_prec);
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::lshift", result, *this, cnt);
+#endif
+
+  return result;
+}
+
+/* Rotate THIS left by Y within its precision.  */
+
+wide_int
+wide_int::lrotate (const wide_int &y) const
+{
+  return lrotate (y.extract_to_hwi (0, HOST_BITS_PER_WIDE_INT));
+}
+
+/* Rotate THIS left by CNT within its precision.  */
+
+wide_int
+wide_int::lrotate (int cnt) const
+{
+  wide_int left, right, result;
+  int prec = precision ();
+
+  left = lshift (cnt, NONE);
+  right = rshiftu (prec - cnt, NONE);
+  result = left | right;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::lrotate", result, *this, cnt);
+#endif
+  return result;
+}
+
+/* Unsigned right shift by Y.  See the definition of Op.TRUNC for how
+   to set Z.  */
+
+wide_int
+wide_int::rshiftu (const wide_int &y, Op z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (mode, &y, TRUNC);
+      if (shift == -1)
+	return wide_int_zero (mode);
+      return rshiftu (shift, NONE);
+    }
+  else
+    return rshiftu (trunc_shift (mode, &y, NONE), NONE);
+}
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set Z.  */
+
+wide_int
+wide_int::rshiftu (int cnt, Op trunc_op) const
+{
+  wide_int result;
+  int prec = precision ();
+  int stop_block, offset, i;
+
+  result.mode = mode;
+
+  if (trunc_op == TRUNC)
+    cnt = trunc_shift (mode, cnt);
+
+  if (cnt == 0)
+    {
+      result = copy (mode);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::rshiftu", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  /* Handle the simple case quickly.   */
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT x = val[0];
+
+      if (prec < HOST_BITS_PER_WIDE_INT)
+	x = zext (x, prec);
+
+      result.val[0] = x >> cnt;
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::rshiftu", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  if (cnt >= prec)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::rshiftu", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (prec - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  offset = (prec - cnt) & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset)
+    result.val[stop_block - 1] = zext (result.val[stop_block - 1], offset);
+  else
+    /* The top block had a 1 at the top position so it will decompress
+       wrong unless a zero block is added.  This only works because we
+       know the shift was greater than 0.  */
+    if (result.val[stop_block - 1] < 0)
+      result.val[result.len++] = 0;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:rshiftu", result, *this, cnt);
+#endif
+  return result;
+}
+
+/* Signed right shift by Y.  See the definition of Op.TRUNC for how to
+   set Z.  */
+wide_int
+wide_int::rshifts (const wide_int &y, Op z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (mode, &y, TRUNC);
+      if (shift == -1)
+	{
+	  /* The value of the shift was larger than the bitsize and this
+	     machine does not truncate the value, so the result is
+	     a smeared sign bit.  */
+	  if (neg_p ())
+	    return wide_int_minus_one (mode);
+	  else
+	    return wide_int_zero (mode);
+	}
+      return rshifts (shift, NONE);
+    }
+  else
+    return rshifts (trunc_shift (mode, &y, NONE), NONE);
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set Z.  */
+
+wide_int
+wide_int::rshifts (int cnt, Op trunc_op) const
+{
+  wide_int result;
+  int prec = precision ();
+  int stop_block, i;
+
+  result.mode = mode;
+
+  if (trunc_op == TRUNC)
+    cnt = trunc_shift (result.mode, cnt);
+
+  if (cnt == 0)
+    {
+      result = copy (mode);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::rshifts", result, *this, cnt);
+#endif
+      return result;
+    }
+  /* Handle the simple case quickly.   */
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT x = val[0];
+      result.val[0] = x >> cnt;
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::rshifts", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  if (cnt >= prec)
+    {
+      HOST_WIDE_INT m = sign_mask ();
+      result.val[0] = m;
+      result.len = 1;
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::rshifts", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (prec - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  /* No need to sign extend the last block, since it extract_to_hwi
+     already did that.  */
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::rshifts", result, *this, cnt);
+#endif
+
+  return result;
+}
+
+/* Rotate THIS right by Y within its precision.  */
+
+wide_int
+wide_int::rrotate (const wide_int &y) const
+{
+  return rrotate (y.extract_to_hwi (0, HOST_BITS_PER_WIDE_INT));
+}
+
+/* Rotate THIS right by CNT within its precision.  */
+
+wide_int
+wide_int::rrotate (int cnt) const
+{
+  wide_int left, right, result;
+  int prec = precision ();
+
+  left = lshift (prec - cnt, NONE);
+  right = rshiftu (cnt, NONE);
+  result = left | right;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::rrotate", result, *this, cnt);
+#endif
+  return result;
+}
+
+/*
+ * Private utilities.
+ */
+/* Decompress THIS for at least TARGET bits into a result with MODE.  */
+
+wide_int
+wide_int::decompress (int target, enum machine_mode mode) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (target);
+  HOST_WIDE_INT mask;
+  int len, i;
+
+  result.mode = mode;
+  result.len = blocks_needed;
+
+  for (i = 0; i < this->len; i++)
+    result.val[i] = val[i];
+
+  len = this->len;
+
+  /* One could argue that this should just ice.  */
+  if (target > GET_MODE_PRECISION (mode))
+    return result;
+
+  /* The extension that we are doing here is not sign extension, it is
+     decompression.  */
+  mask = sign_mask ();
+  while (len < blocks_needed)
+    result.val[len++] = mask;
+
+  return result;
+}
+
+
+/*
+ * Private debug printing routines.
+ */
+
+/* The debugging routines print results of wide operations into the
+   dump files of the respective passes in which they were called.  */
+char *
+wide_int::dump (char* buf) const
+{
+  int i;
+  int l;
+  const char * sep = "";
+
+  l = sprintf (buf, "[%s (", GET_MODE_NAME (mode));
+  for (i = len - 1; i >= 0; i--)
+    {
+      l += sprintf (&buf[l], "%s" HOST_WIDE_INT_PRINT_HEX, sep, val[i]);
+      sep = " ";
+    }
+
+  gcc_assert (len != 0);
+
+  l += sprintf (&buf[l], ")]");
+
+  gcc_assert (l < MAX);
+  return buf;
+}
+
+void
+debug_vw (const char* name, int r, const wide_int& o0)
+{
+  char buf0[MAX];
+  fprintf (dump_file, "%s: %d = %s\n", name, r, o0.dump (buf0));
+}
+
+void
+debug_vwh (const char* name, int r, const wide_int &o0,
+	   HOST_WIDE_INT o1)
+{
+  char buf0[MAX];
+  fprintf (dump_file, "%s: %d = %s 0x"HOST_WIDE_INT_PRINT_HEX" \n", name, r,
+	   o0.dump (buf0), o1);
+}
+
+void
+debug_vww (const char* name, int r, const wide_int &o0,
+	   const wide_int &o1)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  fprintf (dump_file, "%s: %d = %s OP %s\n", name, r,
+	   o0.dump (buf0), o1.dump (buf1));
+}
+
+void
+debug_wv (const char* name, const wide_int &r, int v0)
+{
+  char buf0[MAX];
+  fprintf (dump_file, "%s: %s = %d\n",
+	   name, r.dump (buf0), v0);
+}
+
+void
+debug_wvv (const char* name, const wide_int &r, int v0, int v1)
+{
+  char buf0[MAX];
+  fprintf (dump_file, "%s: %s = %d %d\n",
+	   name, r.dump (buf0), v0, v1);
+}
+
+void
+debug_wvvv (const char* name, const wide_int &r, int v0,
+	    int v1, int v2)
+{
+  char buf0[MAX];
+  fprintf (dump_file, "%s: %s = %d %d %d\n",
+	   name, r.dump (buf0), v0, v1, v2);
+}
+
+void
+debug_wwv (const char* name, const wide_int &r,
+	   const wide_int &o0, int v0)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  fprintf (dump_file, "%s: %s = %s %d\n",
+	   name, r.dump (buf0),
+	   o0.dump (buf1), v0);
+}
+
+void
+debug_wwwvv (const char* name, const wide_int &r,
+	     const wide_int &o0, const wide_int &o1, int v0, int v1)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  char buf2[MAX];
+  fprintf (dump_file, "%s: %s = %s OP %s %d %d\n",
+	   name, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), v0, v1);
+}
+
+void
+debug_ww (const char* name, const wide_int &r, const wide_int &o0)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  fprintf (dump_file, "%s: %s = %s\n",
+	   name, r.dump (buf0),
+	   o0.dump (buf1));
+}
+
+void
+debug_www (const char* name, const wide_int &r,
+	   const wide_int &o0, const wide_int &o1)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  char buf2[MAX];
+  fprintf (dump_file, "%s: %s = %s OP %s\n",
+	   name, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2));
+}
+
+void
+debug_wwwv (const char* name, const wide_int &r,
+	    const wide_int &o0, const wide_int &o1, int v0)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  char buf2[MAX];
+  fprintf (dump_file, "%s: %s = %s OP %s %d\n",
+	   name, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), v0);
+}
+
+void
+debug_wwww (const char* name, const wide_int &r,
+	    const wide_int &o0, const wide_int &o1, const wide_int &o2)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  char buf2[MAX];
+  char buf3[MAX];
+  fprintf (dump_file, "%s: %s = %s OP %s OP %s\n",
+	   name, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), o2.dump (buf3));
+}
+#endif
+
Index: gcc/wide-int.h
===================================================================
--- gcc/wide-int.h	(revision 0)
+++ gcc/wide-int.h	(revision 0)
@@ -0,0 +1,718 @@
+/* Operations with very long integers.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef WIDE_INT_H
+#define WIDE_INT_H
+
+/* A wide integer is currently represented as a vector of
+   HOST_WIDE_INTs.  The vector contains enough elements to hold a
+   value of MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT which is
+   a derived for each host target combination.  The values are stored
+   in the vector with the least signicant HOST_BITS_PER_WIDE_INT bits
+   of the value stored in element 0.
+
+   A wide_int contains four fields: the vector (VAL), the mode and a
+   length, (LEN).  The length is the number of HWIs needed to
+   represent the value.
+
+   Since most integers used in a compiler are small values, it is
+   generally profitable to use a representation of the value that is
+   shorter than the modes precision.  LEN is used to indicate the
+   number of elements of the vector that are in use.  When LEN *
+   HOST_BITS_PER_WIDE_INT < the precision, the value has been
+   compressed.  The values of the elements of the vector greater than
+   LEN - 1. are all equal to the highest order bit of LEN.
+
+   The representation does not contain any information about
+   signedness of the represented value, so it can be used to represent
+   both signed and unsigned numbers.  For operations where the results
+   depend on signedness (division, comparisons), the signedness must
+   be specified separately.  For operations where the signness
+   matters, one of the operands to the operation specifies either
+   wide_int::SIGNED or wide_int::UNSIGNED.
+
+   All constructors for wide_int take either an enum machine_mode or
+   tree_type.  */
+
+
+#ifndef GENERATOR_FILE
+#include "hwint.h"
+#include "options.h"
+#include "tm.h"
+#include "insn-modes.h"
+#include "machmode.h"
+#include "double-int.h"
+#include <gmp.h>
+#include "insn-modes.h"
+
+/* Some useful constants.  */
+
+#define wide_int_minus_one(MODE) (wide_int::from_shwi (-1, MODE))
+#define wide_int_zero(MODE)      (wide_int::from_shwi (0, MODE))
+#define wide_int_one(MODE)       (wide_int::from_shwi (1, MODE))
+#define wide_int_two(MODE)       (wide_int::from_shwi (2, MODE))
+#define wide_int_ten(MODE)       (wide_int::from_shwi (10, MODE))
+
+class wide_int {
+  /* Internal representation.  */
+  HOST_WIDE_INT val[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  unsigned short len;
+  enum machine_mode mode;
+
+ public:
+  enum Op {
+    NONE,
+    /* There are two uses for the wide-int shifting functions.  The
+       first use is as an emulation of the target hardware.  The
+       second use is as service routines for other optimizations.  The
+       first case needs to be identified by passing TRUNC as the value
+       of Op so that shift amount is properly handled according to the
+       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
+       amount is always truncated by the bytesize of the mode of
+       THIS.  */
+    TRUNC,
+
+    /* Many of the math functions produce different results depending
+       on if they are SIGNED or UNSIGNED.  In general, there are two
+       different functions, whose names are prefixed with an 'S" and
+       or an 'U'.  However, for some math functions there is also a
+       routine that does not have the prefix and takes an Op parameter
+       of SIGNED or UNSIGNED.  */
+    SIGNED,
+    UNSIGNED
+  };
+
+  /* Conversions.  */
+
+  static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode);
+  static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, bool *overflow);
+  static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode);
+  static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode, bool *overflow);
+
+  static wide_int from_double_int (enum machine_mode, double_int);
+  static wide_int from_int_cst (const_tree);
+  static wide_int from_rtx (const_rtx, enum machine_mode);
+
+  HOST_WIDE_INT to_shwi () const;
+  HOST_WIDE_INT to_shwi (int prec) const;
+  unsigned HOST_WIDE_INT to_uhwi () const;
+  unsigned HOST_WIDE_INT to_uhwi (int prec) const;
+
+  /* Largest and smallest values that are represented in modes or precisions.  */
+
+  static wide_int max_value (const enum machine_mode mode, Op sgn);
+  static wide_int max_value (const enum machine_mode mode, int prec, Op sgn);
+  static wide_int min_value (const enum machine_mode mode, Op sgn);
+  static wide_int min_value (const enum machine_mode mode, int prec, Op sgn);
+
+  /* Accessors.  */
+
+  inline unsigned short get_len () const;
+  inline void set_len (unsigned int);
+  inline int full_len () const;
+  inline enum machine_mode get_mode () const;
+  inline void set_mode (enum machine_mode m);
+  inline HOST_WIDE_INT& elt_ref (unsigned int i);
+  inline unsigned HOST_WIDE_INT& uelt_ref (unsigned int i);
+  inline const unsigned HOST_WIDE_INT& uelt_ref (unsigned int i) const;
+  inline HOST_WIDE_INT elt (unsigned int i) const;
+  inline int precision () const;
+
+  /* Utility routines.  */
+
+  void canonize ();
+  wide_int copy (enum machine_mode mode) const;
+  static inline HOST_WIDE_INT sext (HOST_WIDE_INT src, int prec);
+  static inline HOST_WIDE_INT zext (HOST_WIDE_INT src, int prec);
+
+  /* Printing functions.  */
+
+  void print_dec (char *buf, Op sgn) const;
+  void print_dec (FILE *file, Op sgn) const;
+  void print_decs (char *buf) const;
+  void print_decs (FILE *file) const;
+  void print_decu (char *buf) const;
+  void print_decu (FILE *file) const;
+  void print_hex (char *buf) const;
+  void print_hex (FILE *file) const;
+
+  /* Comparative functions.  */
+
+  inline bool minus_one_p () const;
+  inline bool zero_p () const;
+  inline bool one_p () const;
+  inline bool neg_p () const;
+  
+  bool operator == (const wide_int &y) const;
+  inline bool operator != (const wide_int &y) const;
+  inline bool gt_p (const HOST_WIDE_INT x, Op sgn) const;
+  inline bool gt_p (const wide_int &x, Op sgn) const;
+  bool gts_p (const HOST_WIDE_INT y) const;
+  inline bool gts_p (const wide_int &y) const;
+  bool gtu_p (const unsigned HOST_WIDE_INT y) const;
+  inline bool gtu_p (const wide_int &y) const;
+
+  inline bool lt_p (const HOST_WIDE_INT x, Op sgn) const;
+  inline bool lt_p (const wide_int &x, Op sgn) const;
+  bool lts_p (const HOST_WIDE_INT y) const;
+  bool lts_p (const wide_int &y) const;
+  bool ltu_p (const unsigned HOST_WIDE_INT y) const;
+  bool ltu_p (const wide_int &y) const;
+
+  bool only_sign_bit_p (int prec) const;
+  bool only_sign_bit_p () const;
+  inline bool fits_uhwi_p () const;
+  inline bool fits_shwi_p () const;
+  bool fits_to_tree_p (const_tree type) const;
+  bool fits_u_p (int prec) const;
+  bool fits_s_p (int prec) const;
+
+  /* Extension  */
+
+  inline wide_int ext (int, Op sgn) const;
+  wide_int sext (int) const;
+  wide_int sext (enum machine_mode mode) const;
+  wide_int zext (int offset) const;
+  wide_int zext (enum machine_mode mode) const;
+
+  /* Masking, and Insertion  */
+
+  wide_int set_bit (int bitpos) const;
+  static wide_int set_bit_in_zero (int, enum machine_mode mode);
+  wide_int insert (const wide_int &op0, int offset, int width) const;
+  static wide_int mask (int, bool, enum machine_mode);
+  wide_int bswap () const;
+  static wide_int shifted_mask (int, int, bool, enum machine_mode);
+  inline HOST_WIDE_INT sign_mask () const;
+
+  /* Logicals */
+
+  wide_int operator & (const wide_int &y) const;
+  wide_int and_not (const wide_int &y) const;
+  wide_int operator ~ () const;
+  wide_int or_not (const wide_int &y) const;
+  wide_int operator | (const wide_int &y) const;
+  wide_int operator ^ (const wide_int &y) const;
+
+  /* Arithmetic operation functions, alpha sorted.  */
+  wide_int abs () const;
+  wide_int operator + (const wide_int &y) const;
+  wide_int operator + (HOST_WIDE_INT y) const;
+  wide_int operator + (unsigned HOST_WIDE_INT y) const;
+  wide_int add (const wide_int &x, Op sgn, bool *overflow) const;
+  wide_int clz (enum machine_mode mode) const;
+  HOST_WIDE_INT clz () const;
+  wide_int clrsb (enum machine_mode mode) const;
+  HOST_WIDE_INT clrsb () const;
+  int cmp (const wide_int &y, Op sgn) const;
+  int cmps (const wide_int &y) const;
+  int cmpu (const wide_int &y) const;
+  wide_int ctz (enum machine_mode mode) const;
+  HOST_WIDE_INT ctz () const;
+  HOST_WIDE_INT exact_log2 () const;
+  HOST_WIDE_INT floor_log2 () const;
+  wide_int ffs () const;
+  wide_int max (const wide_int &y, Op sgn) const;
+  wide_int umax (const wide_int &y) const;
+  wide_int smax (const wide_int &y) const;
+  wide_int min (const wide_int &y, Op sgn) const;
+  wide_int umin (const wide_int &y) const;
+  wide_int smin (const wide_int &y) const;
+  wide_int operator * (const wide_int &y) const;
+  wide_int mul (const wide_int &x, Op sgn, bool *overflow) const;
+  inline wide_int smul (const wide_int &x, bool *overflow) const;
+  inline wide_int umul (const wide_int &x, bool *overflow) const;
+  wide_int mul_full (const wide_int &x, Op sgn) const;
+  inline wide_int umul_full (const wide_int &x) const;
+  inline wide_int smul_full (const wide_int &x) const;
+  wide_int mul_high (const wide_int &x, Op sgn) const;
+  wide_int neg () const;
+  wide_int neg_overflow (bool *z) const;
+  wide_int parity (enum machine_mode m) const;
+  int popcount () const;
+  wide_int popcount (enum machine_mode m) const;
+  wide_int operator - (const wide_int &y) const;
+  wide_int operator - (HOST_WIDE_INT y) const;
+  wide_int operator - (unsigned HOST_WIDE_INT y) const;
+  wide_int sub (const wide_int &x, Op sgn, bool *overflow) const;
+  wide_int truncate (enum machine_mode mode) const;
+
+  /* Divison and mod.  These are the ones that are actually used, but
+     there are a lot of them.  */
+
+  wide_int div_trunc (const wide_int &divisor, Op sgn) const;
+  wide_int div_trunc (const wide_int &divisor, Op sgn, bool *overflow) const;
+  inline wide_int sdiv_trunc (const wide_int &divisor) const;
+  inline wide_int udiv_trunc (const wide_int &divisor) const;
+
+  wide_int div_floor (const wide_int &divisor, Op sgn, bool *overflow) const;
+  inline wide_int udiv_floor (const wide_int &divisor) const;
+  inline wide_int sdiv_floor (const wide_int &divisor) const;
+  wide_int div_ceil (const wide_int &divisor, Op sgn, bool *overflow) const;
+  wide_int div_round (const wide_int &divisor, Op sgn, bool *overflow) const;
+
+  wide_int divmod_trunc (const wide_int &divisor, wide_int *mod, Op sgn) const;
+  inline wide_int sdivmod_trunc (const wide_int &divisor, wide_int *mod) const;
+  inline wide_int udivmod_trunc (const wide_int &divisor, wide_int *mod) const;
+
+  wide_int divmod_floor (const wide_int &divisor, wide_int *mod, Op sgn) const;
+  inline wide_int sdivmod_floor (const wide_int &divisor, wide_int *mod) const;
+
+  wide_int mod_trunc (const wide_int &divisor, Op sgn) const;
+  wide_int mod_trunc (const wide_int &divisor, Op sgn, bool *overflow) const;
+  inline wide_int smod_trunc (const wide_int &divisor) const;
+  inline wide_int umod_trunc (const wide_int &divisor) const;
+
+  wide_int mod_floor (const wide_int &divisor, Op sgn, bool *overflow) const;
+  inline wide_int umod_floor (const wide_int &divisor) const;
+  wide_int mod_ceil (const wide_int &divisor, Op sgn, bool *overflow) const;
+  wide_int mod_round (const wide_int &divisor, Op sgn, bool *overflow) const;
+
+
+  /* Shifting rotating and extracting.  */
+  HOST_WIDE_INT extract_to_hwi (int offset, int width) const;
+
+  wide_int lshift (const wide_int &y, Op z = NONE) const;
+  wide_int lshift (int y, Op z, enum machine_mode m) const;
+  wide_int lshift (int y, Op z = NONE) const;
+
+  wide_int lrotate (const wide_int &y) const;
+  wide_int lrotate (int y) const;
+
+  wide_int rshift (int y, Op sgn) const;
+  inline wide_int rshift (const wide_int &y, Op sgn, Op z = NONE) const;
+  wide_int rshiftu (const wide_int &y, Op z = NONE) const;
+  wide_int rshiftu (int y, Op z = NONE) const;
+  wide_int rshifts (const wide_int &y, Op z = NONE) const;
+  wide_int rshifts (int y, Op z = NONE) const;
+
+  wide_int rrotate (const wide_int &y) const;
+  wide_int rrotate (int y) const;
+
+  static const int DUMP_MAX = (MAX_BITSIZE_MODE_ANY_INT / 4
+			       + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
+  char *dump (char* buf) const;
+ private:
+
+  /* Private utility routines.  */
+  wide_int decompress (int target, enum machine_mode mode) const;
+  static wide_int add_overflow (const wide_int *op0, const wide_int *op1,
+				wide_int::Op sgn, bool *overflow);
+  static wide_int sub_overflow (const wide_int *op0, const wide_int *op1, 
+				wide_int::Op sgn, bool *overflow);
+  static wide_int mul_internal (bool high, bool full, 
+				const wide_int *op1, const wide_int *op2, wide_int::Op op, 
+				bool *overflow, bool needs_overflow);
+};
+
+
+/* Produce 0 or -1 that is the smear of the sign bit.  */
+
+HOST_WIDE_INT
+wide_int::sign_mask () const
+{
+  int prec = GET_MODE_PRECISION (mode);
+  int i = len - 1;
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    return ((val[0] << (HOST_BITS_PER_WIDE_INT - prec))
+	    >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* VRP appears to be badly broken and this is a very ugly fix.  */
+  if (i >= 0)
+    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
+
+  gcc_unreachable ();
+}
+
+#define wide_int_smin(OP0,OP1)  ((OP0).lts_p (OP1) ? (OP0) : (OP1))
+#define wide_int_smax(OP0,OP1)  ((OP0).lts_p (OP1) ? (OP1) : (OP0))
+#define wide_int_umin(OP0,OP1)  ((OP0).ltu_p (OP1) ? (OP0) : (OP1))
+#define wide_int_umax(OP0,OP1)  ((OP0).ltu_p (OP1) ? (OP1) : (OP0))
+
+
+/* Public accessors for the interior of a wide int.  */
+
+/* Get the number of host wide ints actually represented within the
+   wide int.  */
+
+unsigned short
+wide_int::get_len () const
+{
+  return len;
+}
+
+/* Set the number of host wide ints actually represented within the
+   wide int.  */
+
+void
+wide_int::set_len (unsigned int l)
+{
+  gcc_assert (l < MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT);
+  len = l;
+}
+
+/* Get the mode of the wide int.  */
+
+enum machine_mode
+wide_int::get_mode () const
+{
+  return mode;
+}
+
+/* Set the mode of the wide int.  */
+
+void
+wide_int::set_mode (enum machine_mode m)
+{
+  mode = m;
+}
+
+/* Get the number of host wide ints needed to represent the precision
+   of the number.  */
+
+int
+wide_int::full_len () const
+{
+  return ((GET_MODE_PRECISION (mode) + HOST_BITS_PER_WIDE_INT - 1)
+	  / HOST_BITS_PER_WIDE_INT);
+}
+
+/* Get a reference to a particular element of the wide int.  Does not
+   check I against len as during construction we might want to set len
+   after creating the value.  */
+
+HOST_WIDE_INT&
+wide_int::elt_ref (unsigned int i)
+{
+  /* We check maximal size, not len.  */
+  gcc_assert (i < MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT); 
+
+  return val[i];
+}
+
+/* Get a reference to a particular element of the wide int as an
+   unsigned quantity.  Does not check I against len as during
+   construction we might want to set len after creating the value.  */
+
+unsigned HOST_WIDE_INT&
+wide_int::uelt_ref (unsigned int i)
+{
+  return *(unsigned HOST_WIDE_INT *)&elt_ref (i);
+}
+
+/* Get a reference to a particular element of the wide int as a
+   constant unsigned quantity.  Does not check I against len as during
+   construction we might want to set len after creating the value.  */
+
+const unsigned HOST_WIDE_INT&
+wide_int::uelt_ref (unsigned int i) const
+{
+  /* We check maximal size, not len.  */
+  gcc_assert (i < MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT); 
+
+  return *(const unsigned HOST_WIDE_INT *)&val[i];
+}
+
+/* Get a particular element of the wide int.  */
+
+HOST_WIDE_INT
+wide_int::elt (unsigned int i) const
+{
+  return i >= len ? sign_mask () : val[i];
+}
+
+/* Get the precision of the mode in THIS.  */
+int
+wide_int::precision () const
+{
+  return GET_MODE_PRECISION (mode);
+}
+
+
+
+/* Sign extend SRC from PREC.  */
+
+HOST_WIDE_INT
+wide_int::sext (HOST_WIDE_INT src, int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    {
+      int shift = HOST_BITS_PER_WIDE_INT - (prec & (HOST_BITS_PER_WIDE_INT - 1));
+      return (src << shift) >> shift;
+    }
+}
+
+/* Zero extend SRC from PREC.  */
+
+HOST_WIDE_INT
+wide_int::zext (HOST_WIDE_INT src, int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    return src & (((HOST_WIDE_INT)1
+		   << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
+}
+
+bool
+wide_int::minus_one_p () const
+{
+  return len == 1 && val[0] == (HOST_WIDE_INT)-1;
+}
+
+bool
+wide_int::zero_p () const
+{
+  return len == 1 && val[0] == 0;
+}
+
+bool
+wide_int::one_p () const
+{
+  return len == 1 && val[0] == 1;
+}
+
+bool
+wide_int::neg_p () const
+{
+  return sign_mask () != 0;
+}
+
+bool
+wide_int::operator != (const wide_int &op1) const
+{
+  return !(*this == op1);
+}  
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+bool
+wide_int::gt_p (HOST_WIDE_INT op1, Op op) const
+{
+  if (op == SIGNED)
+    return gts_p (op1);
+  else
+    return gtu_p (op1);
+}  
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+bool
+wide_int::gt_p (const wide_int &op1, Op op) const
+{
+  if (op == SIGNED)
+    return op1.lts_p (*this);
+  else
+    return op1.ltu_p (*this);
+}  
+
+/* Return true if THIS is signed greater than OP1.  */
+bool
+wide_int::gts_p (const wide_int &op1) const
+{
+  return op1.lts_p (*this);
+}  
+
+/* Return true if THIS is unsigned greater than OP1.  */
+bool
+wide_int::gtu_p (const wide_int &op1) const
+{
+  return op1.ltu_p (*this);
+}  
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+bool
+wide_int::lt_p (HOST_WIDE_INT op1, Op op) const
+{
+  if (op == SIGNED)
+    return lts_p (op1);
+  else
+    return ltu_p (op1);
+}  
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+bool
+wide_int::lt_p (const wide_int &op1, Op op) const
+{
+  if (op == SIGNED)
+    return lts_p (op1);
+  else
+    return ltu_p (op1);
+}  
+
+/* Return true if THIS fits in a HOST_WIDE_INT with no loss of
+   precision.  */
+bool
+wide_int::fits_shwi_p () const
+{
+  return len == 1;
+}
+
+/* Return true if THIS fits in an unsigned HOST_WIDE_INT with no loss
+   of precision.  */
+bool
+wide_int::fits_uhwi_p () const
+{
+  return len == 1 
+    || (len == 2 && val[1] == (HOST_WIDE_INT)-1);
+}
+
+/* Return THIS extended to PREC.  The signness of the extension is
+   specified by OP.  */
+wide_int 
+wide_int::ext (int prec, Op z) const
+{
+  if (z == UNSIGNED)
+    return zext (prec);
+  else
+    return zext (prec);
+}
+
+/* Signed multiply THIS and OP1.  The result is the same precision as
+   the operands.  OVERFLOW is set true if the result overflows.  */
+wide_int
+wide_int::smul (const wide_int &x, bool *overflow) const
+{
+  return mul (x, SIGNED, overflow);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is the same precision
+   as the operands.  OVERFLOW is set true if the result overflows.  */
+wide_int
+wide_int::umul (const wide_int &x, bool *overflow) const
+{
+  return mul (x, UNSIGNED, overflow);
+}
+
+/* Signed multiply THIS and OP1.  The result is twice the precision as
+   the operands.  There is an issue with this function if it is called
+   on the widest mode defined on the platform, since there is no mode
+   that is twice as wide.  */
+wide_int
+wide_int::smul_full (const wide_int &x) const
+{
+  return mul_full (x, SIGNED);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is twice the precision
+   as the operands.  There is an issue with this function if it is
+   called on the widest mode defined on the platform, since there is
+   no mode that is twice as wide.  */
+wide_int
+wide_int::umul_full (const wide_int &x) const
+{
+  return mul_full (x, UNSIGNED);
+}
+
+/* Signed divide with truncation of result.  */
+wide_int
+wide_int::sdiv_trunc (const wide_int &divisor) const
+{
+  return div_trunc (divisor, SIGNED);
+}
+
+/* Unsigned divide with truncation of result.  */
+wide_int
+wide_int::udiv_trunc (const wide_int &divisor) const
+{
+  return div_trunc (divisor, UNSIGNED);
+}
+
+/* Unsigned divide with floor truncation of result.  */
+wide_int
+wide_int::udiv_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return div_floor (divisor, UNSIGNED, &overflow);
+}
+
+/* Signed divide with floor truncation of result.  */
+wide_int
+wide_int::sdiv_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return div_floor (divisor, SIGNED, &overflow);
+}
+
+/* Signed divide/mod with truncation of result.  */
+wide_int
+wide_int::sdivmod_trunc (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_trunc (divisor, mod, SIGNED);
+}
+
+/* Unsigned divide/mod with truncation of result.  */
+wide_int
+wide_int::udivmod_trunc (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_trunc (divisor, mod, UNSIGNED);
+}
+
+/* Signed divide/mod with floor truncation of result.  */
+wide_int
+wide_int::sdivmod_floor (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_floor (divisor, mod, SIGNED);
+}
+
+/* Signed mod with truncation of result.  */
+wide_int
+wide_int::smod_trunc (const wide_int &divisor) const
+{
+  return mod_trunc (divisor, SIGNED);
+}
+
+/* Unsigned mod with truncation of result.  */
+wide_int
+wide_int::umod_trunc (const wide_int &divisor) const
+{
+  return mod_trunc (divisor, UNSIGNED);
+}
+
+/* Unsigned mod with floor truncation of result.  */
+wide_int
+wide_int::umod_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return mod_floor (divisor, UNSIGNED, &overflow);
+}
+
+wide_int
+wide_int::rshift (const wide_int &y, Op sgn, Op z) const
+{
+  if (sgn == UNSIGNED)
+    return rshiftu (y, z);
+  else
+    return rshifts (y, z);
+}
+
+/* Conversion to and from GMP integer representations.  */
+
+void mpz_set_wide_int (mpz_t, wide_int, bool);
+wide_int mpz_get_wide_int (const_tree, mpz_t, bool);
+#endif /* GENERATOR FILE */
+
+#endif /* WIDE_INT_H */
Index: gcc/genmodes.c
===================================================================
--- gcc/genmodes.c	(revision 191978)
+++ gcc/genmodes.c	(working copy)
@@ -849,6 +849,38 @@ calc_wider_mode (void)
 
 #define print_closer() puts ("};")
 
+/* Compute the max bitsize of some of the classes of integers.  It may
+   be that there are needs for the other integer classes, and this
+   code is easy to extend.  */
+static void
+emit_max_int (void)
+{
+  unsigned int max, mmax;
+  struct mode_data *i;
+  int j;
+
+  puts ("");
+  for (max = 1, i = modes[MODE_INT]; i; i = i->next)
+    if (max < i->bytesize)
+	max = i->bytesize;
+  printf ("#define MAX_BITSIZE_MODE_INT %d*BITS_PER_UNIT\n", max);
+  mmax = max;
+  for (max = 1, i = modes[MODE_PARTIAL_INT]; i; i = i->next)
+    if (max < i->bytesize)
+	max = i->bytesize;
+  printf ("#define MAX_BITSIZE_MODE_PARTIAL_INT %d*BITS_PER_UNIT\n", max);
+  if (max > mmax)
+    mmax = max;
+  printf ("#define MAX_BITSIZE_MODE_ANY_INT %d*BITS_PER_UNIT\n", mmax);
+
+  mmax = 0;
+  for (j = 0; j < MAX_MODE_CLASS; j++)
+    for (i = modes[j]; i; i = i->next)
+      if (mmax < i->bytesize)
+	mmax = i->bytesize;
+  printf ("#define MAX_BITSIZE_MODE_ANY_MODE %d*BITS_PER_UNIT\n", mmax);
+}
+
 static void
 emit_insn_modes_h (void)
 {
@@ -913,6 +945,7 @@ enum machine_mode\n{");
 #endif
   printf ("#define CONST_MODE_IBIT%s\n", adj_ibit ? "" : " const");
   printf ("#define CONST_MODE_FBIT%s\n", adj_fbit ? "" : " const");
+  emit_max_int ();
   puts ("\
 \n\
 #endif /* insn-modes.h */");
Index: gcc/ira-lives.c
===================================================================
--- gcc/ira-lives.c	(revision 191978)
+++ gcc/ira-lives.c	(working copy)
@@ -779,22 +779,16 @@ single_reg_class (const char *constraint
 	  break;
 
 	case 'n':
-	  if (CONST_INT_P (op)
-	      || CONST_DOUBLE_AS_INT_P (op)
-	      || (equiv_const != NULL_RTX
-		  && (CONST_INT_P (equiv_const)
-		      || CONST_DOUBLE_AS_INT_P (equiv_const))))
+	  if (CONST_SCALAR_INT_P (op)
+	      || (equiv_const != NULL_RTX && CONST_SCALAR_INT_P (equiv_const)))
 	    return NO_REGS;
 	  break;
 
 	case 's':
-	  if ((CONSTANT_P (op) 
-	       && !CONST_INT_P (op) 
-	       && !CONST_DOUBLE_AS_INT_P (op))
+	  if ((CONSTANT_P (op) && !CONST_SCALAR_INT_P (op))
 	      || (equiv_const != NULL_RTX
 		  && CONSTANT_P (equiv_const)
-		  && !CONST_INT_P (equiv_const)
-		  && !CONST_DOUBLE_AS_INT_P (equiv_const)))
+		  && !CONST_SCALAR_INT_P (equiv_const)))
 	    return NO_REGS;
 	  break;
 
Index: gcc/emit-rtl.c
===================================================================
--- gcc/emit-rtl.c	(revision 191978)
+++ gcc/emit-rtl.c	(working copy)
@@ -128,6 +128,9 @@ rtx cc0_rtx;
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
      htab_t const_int_htab;
 
+static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
+     htab_t const_wide_int_htab;
+
 /* A hash table storing memory attribute structures.  */
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct mem_attrs)))
      htab_t mem_attrs_htab;
@@ -153,6 +156,11 @@ static void set_used_decls (tree);
 static void mark_label_nuses (rtx);
 static hashval_t const_int_htab_hash (const void *);
 static int const_int_htab_eq (const void *, const void *);
+#if TARGET_SUPPORTS_WIDE_INT
+static hashval_t const_wide_int_htab_hash (const void *);
+static int const_wide_int_htab_eq (const void *, const void *);
+static rtx lookup_const_wide_int (rtx);
+#endif
 static hashval_t const_double_htab_hash (const void *);
 static int const_double_htab_eq (const void *, const void *);
 static rtx lookup_const_double (rtx);
@@ -189,6 +197,43 @@ const_int_htab_eq (const void *x, const
   return (INTVAL ((const_rtx) x) == *((const HOST_WIDE_INT *) y));
 }
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns a hash code for X (which is a really a CONST_WIDE_INT).  */
+
+static hashval_t
+const_wide_int_htab_hash (const void *x)
+{
+  int i;
+  HOST_WIDE_INT hash = 0;
+  const_rtx xr = (const_rtx) x;
+
+  for (i = 0; i < CONST_WIDE_INT_NUNITS (xr); i++)
+    hash += CONST_WIDE_INT_ELT (xr, i);
+
+  return (hashval_t) hash;
+}
+
+/* Returns nonzero if the value represented by X (which is really a
+   CONST_WIDE_INT) is the same as that given by Y (which is really a
+   CONST_WIDE_INT).  */
+
+static int
+const_wide_int_htab_eq (const void *x, const void *y)
+{
+  int i;
+  const_rtx xr = (const_rtx)x;
+  const_rtx yr = (const_rtx)y;
+  if (CONST_WIDE_INT_NUNITS (xr) != CONST_WIDE_INT_NUNITS (yr))
+    return 0;
+
+  for (i = 0; i < CONST_WIDE_INT_NUNITS (xr); i++)
+    if (CONST_WIDE_INT_ELT (xr, i) != CONST_WIDE_INT_ELT (yr, i))
+      return 0;
+  
+  return 1;
+}
+#endif
+
 /* Returns a hash code for X (which is really a CONST_DOUBLE).  */
 static hashval_t
 const_double_htab_hash (const void *x)
@@ -196,7 +241,7 @@ const_double_htab_hash (const void *x)
   const_rtx const value = (const_rtx) x;
   hashval_t h;
 
-  if (GET_MODE (value) == VOIDmode)
+  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (value) == VOIDmode)
     h = CONST_DOUBLE_LOW (value) ^ CONST_DOUBLE_HIGH (value);
   else
     {
@@ -216,7 +261,7 @@ const_double_htab_eq (const void *x, con
 
   if (GET_MODE (a) != GET_MODE (b))
     return 0;
-  if (GET_MODE (a) == VOIDmode)
+  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (a) == VOIDmode)
     return (CONST_DOUBLE_LOW (a) == CONST_DOUBLE_LOW (b)
 	    && CONST_DOUBLE_HIGH (a) == CONST_DOUBLE_HIGH (b));
   else
@@ -482,6 +527,7 @@ const_fixed_from_fixed_value (FIXED_VALU
   return lookup_const_fixed (fixed);
 }
 
+#if TARGET_SUPPORTS_WIDE_INT == 0
 /* Constructs double_int from rtx CST.  */
 
 double_int
@@ -501,17 +547,58 @@ rtx_to_double_int (const_rtx cst)
   
   return r;
 }
+#endif
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Determine whether WIDE_INT, already exists in the hash table.  If
+   so, return its counterpart; otherwise add it to the hash table and
+   return it.  */
 
-/* Return a CONST_DOUBLE or CONST_INT for a value specified as
-   a double_int.  */
-
-rtx
-immed_double_int_const (double_int i, enum machine_mode mode)
+static rtx
+lookup_const_wide_int (rtx wint)
 {
-  return immed_double_const (i.low, i.high, mode);
+  void **slot = htab_find_slot (const_wide_int_htab, wint, INSERT);
+  if (*slot == 0)
+    *slot = wint;
+
+  return (rtx) *slot;
+}
+#endif
+
+/* V contains a wide_int.  A CONST_INT or CONST_WIDE_INT (if
+   TARGET_SUPPORTS_WIDE_INT is defined) or CONST_DOUBLE if
+   TARGET_SUPPORTS_WIDE_INT is not defined is produced based on the
+   number of HOST_WIDE_INTs that are necessary to represent the value
+   in compact form.  */
+rtx
+immed_wide_int_const (const wide_int &v)
+{
+  unsigned int len = v.get_len ();
+
+  if (len < 2)
+    return gen_int_mode (v.elt (0), v.get_mode ());
+
+#if TARGET_SUPPORTS_WIDE_INT
+  {
+    rtx value = const_wide_int_alloc (len);
+    unsigned int i;
+
+    /* It is so tempting to just put the mode in here.  Must control
+       myself ... */
+    PUT_MODE (value, VOIDmode);
+    HWI_PUT_NUM_ELEM (CONST_WIDE_INT_VEC (value), len);
+
+    for (i = 0; i < len; i++)
+      CONST_WIDE_INT_ELT (value, i) = v.elt (i);
+
+    return lookup_const_wide_int (value);
+  }
+#else
+  return immed_double_const (v.elt (0), v.elt (1), v.get_mode ());
+#endif
 }
 
+#if TARGET_SUPPORTS_WIDE_INT == 0
 /* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair
    of ints: I0 is the low-order word and I1 is the high-order word.
    For values that are larger than HOST_BITS_PER_DOUBLE_INT, the
@@ -563,6 +650,7 @@ immed_double_const (HOST_WIDE_INT i0, HO
 
   return lookup_const_double (value);
 }
+#endif
 
 rtx
 gen_rtx_REG (enum machine_mode mode, unsigned int regno)
@@ -1244,7 +1332,7 @@ gen_lowpart_common (enum machine_mode mo
     }
   else if (GET_CODE (x) == SUBREG || REG_P (x)
 	   || GET_CODE (x) == CONCAT || GET_CODE (x) == CONST_VECTOR
-	   || CONST_DOUBLE_P (x) || CONST_INT_P (x))
+	   || CONST_DOUBLE_AS_FLOAT_P (x) || CONST_SCALAR_INT_P (x))
     return simplify_gen_subreg (mode, x, innermode, offset);
 
   /* Otherwise, we can't do this.  */
@@ -5575,11 +5663,15 @@ init_emit_once (void)
   enum machine_mode mode;
   enum machine_mode double_mode;
 
-  /* Initialize the CONST_INT, CONST_DOUBLE, CONST_FIXED, and memory attribute
-     hash tables.  */
+  /* Initialize the CONST_INT, CONST_WIDE_INT, CONST_DOUBLE,
+     CONST_FIXED, and memory attribute hash tables.  */
   const_int_htab = htab_create_ggc (37, const_int_htab_hash,
 				    const_int_htab_eq, NULL);
 
+#if TARGET_SUPPORTS_WIDE_INT
+  const_wide_int_htab = htab_create_ggc (37, const_wide_int_htab_hash,
+					 const_wide_int_htab_eq, NULL);
+#endif
   const_double_htab = htab_create_ggc (37, const_double_htab_hash,
 				       const_double_htab_eq, NULL);
 
Index: gcc/combine.c
===================================================================
--- gcc/combine.c	(revision 191978)
+++ gcc/combine.c	(working copy)
@@ -2617,16 +2617,19 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx
      constant.  */
   if (i1 == 0
       && (temp = single_set (i2)) != 0
-      && (CONST_INT_P (SET_SRC (temp))
-	  || CONST_DOUBLE_AS_INT_P (SET_SRC (temp)))
+      && CONST_SCALAR_INT_P (SET_SRC (temp))
       && GET_CODE (PATTERN (i3)) == SET
-      && (CONST_INT_P (SET_SRC (PATTERN (i3)))
-	  || CONST_DOUBLE_AS_INT_P (SET_SRC (PATTERN (i3))))
+      && CONST_SCALAR_INT_P (SET_SRC (PATTERN (i3)))
       && reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp)))
     {
       rtx dest = SET_DEST (PATTERN (i3));
       int offset = -1;
       int width = 0;
+      
+      /* There are not explicit tests to make sure that this is not a
+	 float, but there is code here that would not be correct if it
+	 was.  */
+      gcc_assert (GET_MODE_CLASS (GET_MODE (SET_SRC (temp))) != MODE_FLOAT);
 
       if (GET_CODE (dest) == ZERO_EXTRACT)
 	{
@@ -2662,23 +2665,15 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx
 	    offset = -1;
 	}
 
-      if (offset >= 0
-	  && (GET_MODE_PRECISION (GET_MODE (SET_DEST (temp)))
-	      <= HOST_BITS_PER_DOUBLE_INT))
+      if (offset >= 0)
 	{
-	  double_int m, o, i;
+	  wide_int o;
 	  rtx inner = SET_SRC (PATTERN (i3));
 	  rtx outer = SET_SRC (temp);
-
-	  o = rtx_to_double_int (outer);
-	  i = rtx_to_double_int (inner);
-
-	  m = double_int::mask (width);
-	  i &= m;
-	  m = m.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
-	  i = i.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
-	  o = o.and_not (m) | i;
-
+	  
+	  o = (wide_int::from_rtx (outer, GET_MODE (SET_DEST (temp)))
+	       .insert (wide_int::from_rtx (inner, GET_MODE (dest)),
+			offset, width));
 	  combine_merges++;
 	  subst_insn = i3;
 	  subst_low_luid = DF_INSN_LUID (i2);
@@ -2689,8 +2684,7 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx
 	  /* Replace the source in I2 with the new constant and make the
 	     resulting insn the new pattern for I3.  Then skip to where we
 	     validate the pattern.  Everything was set up above.  */
-	  SUBST (SET_SRC (temp),
-		 immed_double_int_const (o, GET_MODE (SET_DEST (temp))));
+	  SUBST (SET_SRC (temp), immed_wide_int_const (o));
 
 	  newpat = PATTERN (i2);
 
@@ -5102,8 +5096,7 @@ subst (rtx x, rtx from, rtx to, int in_d
 	      if (GET_CODE (new_rtx) == CLOBBER && XEXP (new_rtx, 0) == const0_rtx)
 		return new_rtx;
 
-	      if (GET_CODE (x) == SUBREG
-		  && (CONST_INT_P (new_rtx) || CONST_DOUBLE_AS_INT_P (new_rtx)))
+	      if (GET_CODE (x) == SUBREG && CONST_SCALAR_INT_P (new_rtx))
 		{
 		  enum machine_mode mode = GET_MODE (x);
 
@@ -5113,7 +5106,7 @@ subst (rtx x, rtx from, rtx to, int in_d
 		  if (! x)
 		    x = gen_rtx_CLOBBER (mode, const0_rtx);
 		}
-	      else if (CONST_INT_P (new_rtx)
+	      else if (CONST_SCALAR_INT_P (new_rtx)
 		       && GET_CODE (x) == ZERO_EXTEND)
 		{
 		  x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
@@ -7133,7 +7126,7 @@ make_extraction (enum machine_mode mode,
       if (mode == tmode)
 	return new_rtx;
 
-      if (CONST_INT_P (new_rtx) || CONST_DOUBLE_AS_INT_P (new_rtx))
+      if (CONST_SCALAR_INT_P (new_rtx))
 	return simplify_unary_operation (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
 					 mode, new_rtx, tmode);
 
@@ -10672,8 +10665,7 @@ gen_lowpart_for_combine (enum machine_mo
   /* We can only support MODE being wider than a word if X is a
      constant integer or has a mode the same size.  */
   if (GET_MODE_SIZE (omode) > UNITS_PER_WORD
-      && ! ((CONST_INT_P (x) || CONST_DOUBLE_AS_INT_P (x))
-	    || isize == osize))
+      && ! (CONST_SCALAR_INT_P (x) || isize == osize))
     goto fail;
 
   /* X might be a paradoxical (subreg (mem)).  In that case, gen_lowpart
Index: gcc/print-rtl.c
===================================================================
--- gcc/print-rtl.c	(revision 191978)
+++ gcc/print-rtl.c	(working copy)
@@ -634,6 +634,12 @@ print_rtx (const_rtx in_rtx)
 	  fprintf (outfile, " [%s]", s);
 	}
       break;
+
+    case CONST_WIDE_INT:
+      if (! flag_simple)
+	fprintf (outfile, " ");
+      hwivec_output_hex (outfile, CONST_WIDE_INT_VEC (in_rtx));
+      break;
 #endif
 
     case CODE_LABEL:
Index: gcc/genpreds.c
===================================================================
--- gcc/genpreds.c	(revision 191978)
+++ gcc/genpreds.c	(working copy)
@@ -613,7 +613,7 @@ write_one_predicate_function (struct pre
   add_mode_tests (p);
 
   /* A normal predicate can legitimately not look at enum machine_mode
-     if it accepts only CONST_INTs and/or CONST_DOUBLEs.  */
+     if it accepts only CONST_INTs and/or CONST_WIDE_INT and/or CONST_DOUBLEs.  */
   printf ("int\n%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n{\n",
 	  p->name);
   write_predicate_stmts (p->exp);
@@ -810,8 +810,11 @@ add_constraint (const char *name, const
   if (is_const_int || is_const_dbl)
     {
       enum rtx_code appropriate_code
+#if TARGET_SUPPORTS_WIDE_INT
+	= is_const_int ? CONST_INT : CONST_WIDE_INT;
+#else
 	= is_const_int ? CONST_INT : CONST_DOUBLE;
-
+#endif
       /* Consider relaxing this requirement in the future.  */
       if (regclass
 	  || GET_CODE (exp) != AND
@@ -1075,12 +1078,17 @@ write_tm_constrs_h (void)
 	if (needs_ival)
 	  puts ("  if (CONST_INT_P (op))\n"
 		"    ival = INTVAL (op);");
+#if TARGET_SUPPORTS_WIDE_INT
+	if (needs_lval || needs_hval)
+	  error ("you can't use lval or hval");
+#else
 	if (needs_hval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)"
 		"    hval = CONST_DOUBLE_HIGH (op);");
 	if (needs_lval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)"
 		"    lval = CONST_DOUBLE_LOW (op);");
+#endif
 	if (needs_rval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode != VOIDmode)"
 		"    rval = CONST_DOUBLE_REAL_VALUE (op);");
Index: gcc/tree-ssa-address.c
===================================================================
--- gcc/tree-ssa-address.c	(revision 191978)
+++ gcc/tree-ssa-address.c	(working copy)
@@ -192,15 +192,16 @@ addr_for_mem_ref (struct mem_address *ad
   struct mem_addr_template *templ;
 
   if (addr->step && !integer_onep (addr->step))
-    st = immed_double_int_const (tree_to_double_int (addr->step), pointer_mode);
+    st = immed_wide_int_const (wide_int::from_int_cst (addr->step));
   else
     st = NULL_RTX;
 
   if (addr->offset && !integer_zerop (addr->offset))
-    off = immed_double_int_const
-	    (tree_to_double_int (addr->offset)
-	     .sext (TYPE_PRECISION (TREE_TYPE (addr->offset))),
-	     pointer_mode);
+    {
+      wide_int dc = wide_int::from_int_cst (addr->offset);
+      dc = dc.sext (TYPE_PRECISION (TREE_TYPE (addr->offset)));
+      off = immed_wide_int_const (dc);
+    }
   else
     off = NULL_RTX;
 
Index: gcc/ggc-zone.c
===================================================================
--- gcc/ggc-zone.c	(revision 191978)
+++ gcc/ggc-zone.c	(working copy)
@@ -1373,6 +1373,9 @@ ggc_alloc_typed_stat (enum gt_types_enum
     case gt_ggc_e_9rtvec_def:
       return ggc_internal_alloc_zone_pass_stat (size, &rtl_zone);
 
+    case gt_ggc_e_10hwivec_def:
+      return ggc_internal_alloc_zone_pass_stat (size, &rtl_zone);
+
     default:
       return ggc_internal_alloc_zone_pass_stat (size, &main_zone);
     }
Index: gcc/final.c
===================================================================
--- gcc/final.c	(revision 191978)
+++ gcc/final.c	(working copy)
@@ -3728,8 +3728,16 @@ output_addr_const (FILE *file, rtx x)
       output_addr_const (file, XEXP (x, 0));
       break;
 
+    case CONST_WIDE_INT:
+      /* This should be ok for a while.  */
+      gcc_assert (CONST_WIDE_INT_NUNITS (x) == 2);
+      fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
+	       (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, 1),
+	       (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, 0));
+      break;
+
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
+      if (CONST_DOUBLE_AS_INT_P (x))
 	{
 	  /* We can use %d if the number is one word and positive.  */
 	  if (CONST_DOUBLE_HIGH (x))
Index: gcc/coretypes.h
===================================================================
--- gcc/coretypes.h	(revision 191978)
+++ gcc/coretypes.h	(working copy)
@@ -56,6 +56,9 @@ typedef const struct rtx_def *const_rtx;
 struct rtvec_def;
 typedef struct rtvec_def *rtvec;
 typedef const struct rtvec_def *const_rtvec;
+struct hwivec_def;
+typedef struct hwivec_def *hwivec;
+typedef const struct hwivec_def *const_hwivec;
 union tree_node;
 typedef union tree_node *tree;
 union gimple_statement_d;
Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(revision 191978)
+++ gcc/expr.c	(working copy)
@@ -719,23 +719,23 @@ convert_modes (enum machine_mode mode, e
   if (mode == oldmode)
     return x;
 
-  /* There is one case that we must handle specially: If we are converting
-     a CONST_INT into a mode whose size is twice HOST_BITS_PER_WIDE_INT and
-     we are to interpret the constant as unsigned, gen_lowpart will do
-     the wrong if the constant appears negative.  What we want to do is
-     make the high-order word of the constant zero, not all ones.  */
+  /* There is one case that we must handle specially: If we are
+     converting a CONST_INT into a mode whose size is larger than
+     HOST_BITS_PER_WIDE_INT and we are to interpret the constant as
+     unsigned, gen_lowpart will do the wrong if the constant appears
+     negative.  What we want to do is make the high-order word of the
+     constant zero, not all ones.  */
 
   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
-      && GET_MODE_BITSIZE (mode) == HOST_BITS_PER_DOUBLE_INT
+      && GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT
       && CONST_INT_P (x) && INTVAL (x) < 0)
     {
-      double_int val = double_int::from_uhwi (INTVAL (x));
-
+      HOST_WIDE_INT val = INTVAL (x);
       /* We need to zero extend VAL.  */
       if (oldmode != VOIDmode)
-	val = val.zext (GET_MODE_BITSIZE (oldmode));
+	val &= GET_MODE_PRECISION (oldmode) - 1;
 
-      return immed_double_int_const (val, mode);
+      return immed_wide_int_const (wide_int::from_uhwi (val, mode));
     }
 
   /* We can do this with a gen_lowpart if both desired and current modes
@@ -747,7 +747,11 @@ convert_modes (enum machine_mode mode, e
        && GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT)
       || (GET_MODE_CLASS (mode) == MODE_INT
 	  && GET_MODE_CLASS (oldmode) == MODE_INT
-	  && (CONST_DOUBLE_AS_INT_P (x) 
+#if TARGET_SUPPORTS_WIDE_INT
+	  && (CONST_WIDE_INT_P (x)
+#else
+ 	  && (CONST_DOUBLE_AS_INT_P (x)
+#endif
 	      || (GET_MODE_PRECISION (mode) <= GET_MODE_PRECISION (oldmode)
 		  && ((MEM_P (x) && ! MEM_VOLATILE_P (x)
 		       && direct_load[(int) mode])
@@ -1752,6 +1756,7 @@ emit_group_load_1 (rtx *tmps, rtx dst, r
 	    {
 	      rtx first, second;
 
+	      /* TODO: const_wide_int can have sizes other than this...  */
 	      gcc_assert (2 * len == ssize);
 	      split_double (src, &first, &second);
 	      if (i)
@@ -5180,10 +5185,10 @@ store_expr (tree exp, rtx target, int ca
 			       &alt_rtl);
     }
 
-  /* If TEMP is a VOIDmode constant and the mode of the type of EXP is not
-     the same as that of TARGET, adjust the constant.  This is needed, for
-     example, in case it is a CONST_DOUBLE and we want only a word-sized
-     value.  */
+  /* If TEMP is a VOIDmode constant and the mode of the type of EXP is
+     not the same as that of TARGET, adjust the constant.  This is
+     needed, for example, in case it is a CONST_DOUBLE or
+     CONST_WIDE_INT and we want only a word-sized value.  */
   if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode
       && TREE_CODE (exp) != ERROR_MARK
       && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
@@ -7711,11 +7716,12 @@ expand_constructor (tree exp, rtx target
 
   /* All elts simple constants => refer to a constant in memory.  But
      if this is a non-BLKmode mode, let it store a field at a time
-     since that should make a CONST_INT or CONST_DOUBLE when we
-     fold.  Likewise, if we have a target we can use, it is best to
-     store directly into the target unless the type is large enough
-     that memcpy will be used.  If we are making an initializer and
-     all operands are constant, put it in memory as well.
+     since that should make a CONST_INT, CONST_WIDE_INT or
+     CONST_DOUBLE when we fold.  Likewise, if we have a target we can
+     use, it is best to store directly into the target unless the type
+     is large enough that memcpy will be used.  If we are making an
+     initializer and all operands are constant, put it in memory as
+     well.
 
      FIXME: Avoid trying to fill vector constructors piece-meal.
      Output them with output_constant_def below unless we're sure
@@ -8207,17 +8213,18 @@ expand_expr_real_2 (sepops ops, rtx targ
 	      && TREE_CONSTANT (treeop1))
 	    {
 	      rtx constant_part;
+	      HOST_WIDE_INT wc;
+	      enum machine_mode wmode = TYPE_MODE (TREE_TYPE (treeop1));
 
 	      op1 = expand_expr (treeop1, subtarget, VOIDmode,
 				 EXPAND_SUM);
-	      /* Use immed_double_const to ensure that the constant is
+	      /* Use wide_int::from_shwi to ensure that the constant is
 		 truncated according to the mode of OP1, then sign extended
 		 to a HOST_WIDE_INT.  Using the constant directly can result
 		 in non-canonical RTL in a 64x32 cross compile.  */
-	      constant_part
-		= immed_double_const (TREE_INT_CST_LOW (treeop0),
-				      (HOST_WIDE_INT) 0,
-				      TYPE_MODE (TREE_TYPE (treeop1)));
+	      wc = TREE_INT_CST_LOW (treeop0);
+	      constant_part 
+		= immed_wide_int_const (wide_int::from_shwi (wc, wmode));
 	      op1 = plus_constant (mode, op1, INTVAL (constant_part));
 	      if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
 		op1 = force_operand (op1, target);
@@ -8229,7 +8236,8 @@ expand_expr_real_2 (sepops ops, rtx targ
 		   && TREE_CONSTANT (treeop0))
 	    {
 	      rtx constant_part;
-
+	      HOST_WIDE_INT wc;
+	      enum machine_mode wmode = TYPE_MODE (TREE_TYPE (treeop0));
 	      op0 = expand_expr (treeop0, subtarget, VOIDmode,
 				 (modifier == EXPAND_INITIALIZER
 				 ? EXPAND_INITIALIZER : EXPAND_SUM));
@@ -8243,14 +8251,13 @@ expand_expr_real_2 (sepops ops, rtx targ
 		    return simplify_gen_binary (PLUS, mode, op0, op1);
 		  goto binop2;
 		}
-	      /* Use immed_double_const to ensure that the constant is
+	      /* Use wide_int::from_shwi to ensure that the constant is
 		 truncated according to the mode of OP1, then sign extended
 		 to a HOST_WIDE_INT.  Using the constant directly can result
 		 in non-canonical RTL in a 64x32 cross compile.  */
-	      constant_part
-		= immed_double_const (TREE_INT_CST_LOW (treeop1),
-				      (HOST_WIDE_INT) 0,
-				      TYPE_MODE (TREE_TYPE (treeop0)));
+	      wc = TREE_INT_CST_LOW (treeop1);
+	      constant_part 
+		= immed_wide_int_const (wide_int::from_shwi (wc, wmode));
 	      op0 = plus_constant (mode, op0, INTVAL (constant_part));
 	      if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
 		op0 = force_operand (op0, target);
@@ -8752,10 +8759,13 @@ expand_expr_real_2 (sepops ops, rtx targ
 	 for unsigned bitfield expand this as XOR with a proper constant
 	 instead.  */
       if (reduce_bit_field && TYPE_UNSIGNED (type))
-	temp = expand_binop (mode, xor_optab, op0,
-			     immed_double_int_const
-			       (double_int::mask (TYPE_PRECISION (type)), mode),
-			     target, 1, OPTAB_LIB_WIDEN);
+	{
+	  wide_int mask = wide_int::mask (TYPE_PRECISION (type), false, mode);
+
+	  temp = expand_binop (mode, xor_optab, op0,
+			       immed_wide_int_const (mask),
+			       target, 1, OPTAB_LIB_WIDEN);
+	}
       else
 	temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
       gcc_assert (temp);
@@ -9335,9 +9345,7 @@ expand_expr_real_1 (tree exp, rtx target
       return decl_rtl;
 
     case INTEGER_CST:
-      temp = immed_double_const (TREE_INT_CST_LOW (exp),
-				 TREE_INT_CST_HIGH (exp), mode);
-
+      temp = immed_wide_int_const (wide_int::from_int_cst (exp));
       return temp;
 
     case VECTOR_CST:
@@ -9568,8 +9576,9 @@ expand_expr_real_1 (tree exp, rtx target
 	op0 = memory_address_addr_space (address_mode, op0, as);
 	if (!integer_zerop (TREE_OPERAND (exp, 1)))
 	  {
-	    rtx off
-	      = immed_double_int_const (mem_ref_offset (exp), address_mode);
+	    wide_int wi = wide_int::from_double_int
+	      (address_mode, mem_ref_offset (exp));
+	    rtx off = immed_wide_int_const (wi);
 	    op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
 	  }
 	op0 = memory_address_addr_space (mode, op0, as);
@@ -10441,8 +10450,8 @@ reduce_to_bit_field_precision (rtx exp,
     }
   else if (TYPE_UNSIGNED (type))
     {
-      rtx mask = immed_double_int_const (double_int::mask (prec),
-					 GET_MODE (exp));
+      rtx mask = immed_wide_int_const 
+	(wide_int::mask (prec, false, GET_MODE (exp)));
       return expand_and (GET_MODE (exp), exp, mask, target);
     }
   else
@@ -11007,8 +11016,8 @@ const_vector_from_tree (tree exp)
 	RTVEC_ELT (v, i) = CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (elt),
 							 inner);
       else
-	RTVEC_ELT (v, i) = immed_double_int_const (tree_to_double_int (elt),
-						   inner);
+	RTVEC_ELT (v, i) 
+	  = immed_wide_int_const (wide_int::from_int_cst (elt));
     }
 
   return gen_rtx_CONST_VECTOR (mode, v);
Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	(revision 191978)
+++ gcc/optabs.c	(working copy)
@@ -838,7 +838,8 @@ expand_subword_shift (enum machine_mode
   if (CONSTANT_P (op1) || shift_mask >= BITS_PER_WORD)
     {
       carries = outof_input;
-      tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
+      tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD,
+						       op1_mode));
       tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
 				   0, true, methods);
     }
@@ -853,13 +854,14 @@ expand_subword_shift (enum machine_mode
 			      outof_input, const1_rtx, 0, unsignedp, methods);
       if (shift_mask == BITS_PER_WORD - 1)
 	{
-	  tmp = immed_double_const (-1, -1, op1_mode);
+	  tmp = immed_wide_int_const (wide_int_minus_one (op1_mode));
 	  tmp = simplify_expand_binop (op1_mode, xor_optab, op1, tmp,
 				       0, true, methods);
 	}
       else
 	{
-	  tmp = immed_double_const (BITS_PER_WORD - 1, 0, op1_mode);
+	  tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD - 1,
+							   op1_mode));
 	  tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
 				       0, true, methods);
 	}
@@ -1022,7 +1024,7 @@ expand_doubleword_shift (enum machine_mo
      is true when the effective shift value is less than BITS_PER_WORD.
      Set SUPERWORD_OP1 to the shift count that should be used to shift
      OUTOF_INPUT into INTO_TARGET when the condition is false.  */
-  tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
+  tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD, op1_mode));
   if (!CONSTANT_P (op1) && shift_mask == BITS_PER_WORD - 1)
     {
       /* Set CMP1 to OP1 & BITS_PER_WORD.  The result is zero iff OP1
@@ -2872,7 +2874,7 @@ expand_absneg_bit (enum rtx_code code, e
   const struct real_format *fmt;
   int bitpos, word, nwords, i;
   enum machine_mode imode;
-  double_int mask;
+  wide_int mask;
   rtx temp, insns;
 
   /* The format has to have a simple sign bit.  */
@@ -2908,7 +2910,7 @@ expand_absneg_bit (enum rtx_code code, e
       nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
     }
 
-  mask = double_int_zero.set_bit (bitpos);
+  mask = wide_int::set_bit_in_zero (bitpos, imode);
   if (code == ABS)
     mask = ~mask;
 
@@ -2930,7 +2932,7 @@ expand_absneg_bit (enum rtx_code code, e
 	    {
 	      temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
 				   op0_piece,
-				   immed_double_int_const (mask, imode),
+				   immed_wide_int_const (mask),
 				   targ_piece, 1, OPTAB_LIB_WIDEN);
 	      if (temp != targ_piece)
 		emit_move_insn (targ_piece, temp);
@@ -2948,7 +2950,7 @@ expand_absneg_bit (enum rtx_code code, e
     {
       temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
 			   gen_lowpart (imode, op0),
-			   immed_double_int_const (mask, imode),
+			   immed_wide_int_const (mask),
 		           gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
       target = lowpart_subreg_maybe_copy (mode, temp, imode);
 
@@ -3547,7 +3549,7 @@ expand_copysign_absneg (enum machine_mod
     }
   else
     {
-      double_int mask;
+      wide_int mask;
 
       if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
 	{
@@ -3569,10 +3571,9 @@ expand_copysign_absneg (enum machine_mod
 	  op1 = operand_subword_force (op1, word, mode);
 	}
 
-      mask = double_int_zero.set_bit (bitpos);
-
+      mask = wide_int::set_bit_in_zero (bitpos, imode);
       sign = expand_binop (imode, and_optab, op1,
-			   immed_double_int_const (mask, imode),
+			   immed_wide_int_const (mask),
 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
 
@@ -3616,7 +3617,7 @@ expand_copysign_bit (enum machine_mode m
 		     int bitpos, bool op0_is_abs)
 {
   enum machine_mode imode;
-  double_int mask;
+  wide_int mask, nmask;
   int word, nwords, i;
   rtx temp, insns;
 
@@ -3640,7 +3641,7 @@ expand_copysign_bit (enum machine_mode m
       nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
     }
 
-  mask = double_int_zero.set_bit (bitpos);
+  mask = wide_int::set_bit_in_zero (bitpos, imode);
 
   if (target == 0
       || target == op0
@@ -3660,14 +3661,16 @@ expand_copysign_bit (enum machine_mode m
 	  if (i == word)
 	    {
 	      if (!op0_is_abs)
-		op0_piece
-		  = expand_binop (imode, and_optab, op0_piece,
-				  immed_double_int_const (~mask, imode),
-				  NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
+		{
+		  nmask = ~mask;
+  		  op0_piece
+		    = expand_binop (imode, and_optab, op0_piece,
+				    immed_wide_int_const (nmask),
+				    NULL_RTX, 1, OPTAB_LIB_WIDEN);
+		}
 	      op1 = expand_binop (imode, and_optab,
 				  operand_subword_force (op1, i, mode),
-				  immed_double_int_const (mask, imode),
+				  immed_wide_int_const (mask),
 				  NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
 	      temp = expand_binop (imode, ior_optab, op0_piece, op1,
@@ -3687,15 +3690,17 @@ expand_copysign_bit (enum machine_mode m
   else
     {
       op1 = expand_binop (imode, and_optab, gen_lowpart (imode, op1),
-		          immed_double_int_const (mask, imode),
+		          immed_wide_int_const (mask),
 		          NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
       op0 = gen_lowpart (imode, op0);
       if (!op0_is_abs)
-	op0 = expand_binop (imode, and_optab, op0,
-			    immed_double_int_const (~mask, imode),
-			    NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
+	{
+	  nmask = ~mask;
+	  op0 = expand_binop (imode, and_optab, op0,
+			      immed_wide_int_const (nmask),
+			      NULL_RTX, 1, OPTAB_LIB_WIDEN);
+	}
       temp = expand_binop (imode, ior_optab, op0, op1,
 			   gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
       target = lowpart_subreg_maybe_copy (mode, temp, imode);
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c	(revision 191978)
+++ gcc/cfgexpand.c	(working copy)
@@ -3633,9 +3633,8 @@ expand_debug_locations (void)
 
 	    gcc_assert (mode == GET_MODE (val)
 			|| (GET_MODE (val) == VOIDmode
-			    && (CONST_INT_P (val)
+			    && (CONST_SCALAR_INT_P (val)
 				|| GET_CODE (val) == CONST_FIXED
-				|| CONST_DOUBLE_AS_INT_P (val) 
 				|| GET_CODE (val) == LABEL_REF)));
 	  }
 
Index: gcc/ggc.h
===================================================================
--- gcc/ggc.h	(revision 191978)
+++ gcc/ggc.h	(working copy)
@@ -271,6 +271,11 @@ extern struct alloc_zone tree_id_zone;
 			    + ((NELT) - 1) * sizeof (rtx),		\
 			    &rtl_zone)
 
+#define ggc_alloc_hwivec_sized(NELT)                                      \
+  ggc_alloc_zone_hwivec_def (sizeof (struct hwivec_def)			\
+			    + ((NELT) - 1) * sizeof (HOST_WIDE_INT),	\
+			    &rtl_zone)
+
 #if defined (GGC_ZONE) && !defined (GENERATOR_FILE)
 
 /* Allocate an object into the specified allocation zone.  */

[-- Attachment #3: rtl3.clog --]
[-- Type: text/plain, Size: 5426 bytes --]

2012-10-3  Kenneth Zadeck <zadeck@naturalbridge.com>

	* reload.c (find_reloads): Use CONST_SCALAR_INT_P.
	rtl.def (CONST_WIDE_INT): New.
	* ira-costs.c (record_reg_classes, record_address_regs):
	Use CONST_SCALAR_INT_P.
	* dojump.c (prefer_and_bit_test): Use wide int api.
	* recog.c (simplify_while_replacing): Use CONST_SCALAR_INT_P.
 	(const_scalar_int_operand, const_double_operand): New versions
	if target supports wide integers.
	(const_wide_int_operand): New function.
	(asm_operand_ok, constrain_operands): Use CONST_SCALAR_INT_P.
	* rtl.c (DEF_RTL_EXPR): Added CONST_WIDE_INT case.
	(rtx_size): Ditto.
	(rtx_alloc_stat, hwivec_output_hex, hwivec_check_failed_bounds):
	New functions.
	(iterative_hash_rtx): Added CONST_WIDE_INT case.
	* rtl.h (hwivec_def): New function.
	(HWI_GET_NUM_ELEM, HWI_PUT_NUM_ELEM, CONST_WIDE_INT_P,
	CONST_SCALAR_INT_P, XHWIVEC_ELT, HWIVEC_CHECK, CONST_WIDE_INT_VEC,
	CONST_WIDE_INT_NUNITS, CONST_WIDE_INT_ELT, rtx_alloc_v): New macros.
	(chain_next): Added hwiv case.
	(CASE_CONST_SCALAR_INT, CONST_INT, CONST_WIDE_INT):  Added new
	defs if target supports wide ints.
	* rtlanal.c (commutative_operand_precedence): Added CONST_WIDE_INT
	case.
	* Makefile.in (wide-int.c, wide-int.h): New files.
	* sched-vis.c (print_value): Added CONST_WIDE_INT case are
	modified DOUBLE_INT case.
	* gengtype.c (wide-int): New type.
	* alias.c  (rtx_equal_for_memref_p): Fixed comment.
	* sel-sched-ir.c (lhs_and_rhs_separable_p): Ditto.
	* genemit.c (gen_exp): Added CONST_WIDE_INT case.
	* defaults.h (TARGET_SUPPORTS_WIDE_INT): New.
	* builtins.c (c_getstr, c_readstr, expand_builtin_signbit): 
	Make to work with any size int.
	* simplify-rtx.c (mode_signbit_p, simplify_unary_operation_1,
	simplify_const_unary_operation, simplify_binary_operation_1,
	simplify_const_binary_operation,
	simplify_relational_operation_1,
	simplify_const_relational_operation, simplify_immed_subreg,
	simplify_subreg): Ditto.
	* gengenrtl.c (excluded_rtx): Added CONST_WIDE_INT case.
	* expmed.c (mask_rtx, lshift_value): Now uses wide-int.
 	(expand_mult, expand_smod_pow2): Make to work with any size int.
	(make_tree): Added CONST_WIDE_INT case.
	* cselib.c (entry_and_rtx_equal_p): Use CONST_SCALAR_INT_P.
	(rtx_equal_for_cselib_1, cselib_hash_rtx): Added CONST_WIDE_INT case.
	* explow.c (plus_constant): Now uses wide-int api.
	* varasm.c (const_rtx_hash_1): Added CONST_WIDE_INT case.
	* hwint.c (popcount_hwi): New function.
	* hwint.h (HOST_BITS_PER_HALF_WIDE_INT, HOST_HALF_WIDE_INT,
	HOST_HALF_WIDE_INT_PRINT, HOST_HALF_WIDE_INT_PRINT_C,
	HOST_HALF_WIDE_INT_PRINT_DEC, HOST_HALF_WIDE_INT_PRINT_DEC_C,
	HOST_HALF_WIDE_INT_PRINT_UNSIGNED, HOST_HALF_WIDE_INT_PRINT_HEX,
	HOST_HALF_WIDE_INT_PRINT_HEX_PURE): New symbols.
	* postreload.c (reload_cse_simplify_set):  Now uses wide-int api.
	* var-tracking.c (loc_cmp): Added CONST_WIDE_INT case.
	* tree.c (wide_int_to_tree): New function.
	* tree.h (wide_int_to_tree): Ditto.
	* gensupport.c (const_wide_int_operand,
	const_scalar_int_operand): New
	* read-rtl.c (validate_const_wide_int): New function.
	(read_rtx_code): Added CONST_WIDE_INT case.
	* cse.c (hash_rtx_cb): Added CONST_WIDE_INT case are
	modified DOUBLE_INT case.
	* dwarf2out.c (dw_val_equal_p, size_of_loc_descr,
	output_loc_operands, print_die, attr_checksum, same_dw_val_p,
	size_of_die, value_format, output_die, mem_loc_descriptor,
	loc_descriptor, extract_int, add_const_value_attribute,
	hash_loc_operands, compare_loc_operands): Add support for wide-ints.
	(add_AT_wide): New function.
	* dwarf2out.h (enum dw_val_class): Added dw_val_class_wide_int.
	* wide-int.c (all): New file.
	* wide-int.h (all): New file.
	* genmodes.c (emit_max_int): New function.
	(emit_insn_modes_h): Add call to emit_max_int.
	* ira-lives.c (single_reg_class):  Use CONST_SCALAR_INT_P.
	* emit-rtl.c (const_wide_int_htab): Add marking.
	(const_wide_int_htab_hash, const_wide_int_htab_eq,
	lookup_const_wide_int, immed_wide_int_const): New functions.
	(const_double_htab_hash, const_double_htab_eq,
	rtx_to_double_int, immed_double_const): Conditionally 
	changed CONST_DOUBLE behavior.
 	(immed_double_const, init_emit_once): Changed to support wide-int.
	* combine.c (try_combine, subst, make_extraction, 
	gen_lowpart_for_combine): Changed to support any size integer.
	* print-rtl.c (print_rtx): Added CONST_WIDE_INT case.
	* genpreds.c (write_one_predicate_function): Fixed comment.
	(add_constraint): Added CONST_WIDE_INT test.
	(write_tm_constrs_h): Do not emit hval or lval if target
	supports wide integers.
	* tree-ssa-address.c (addr_for_mem_ref): Changes to use
	wide-int rather than double-int.
	* ggc-zone.c (ggc_alloc_typed_stat): Added
	gt_ggc_e_10hwivec_def case.
	* final.c (output_addr_const): Added CONST_WIDE_INT case.
	* coretypes.h (hwivec_def, hwivec, const_hwivec): New.
	* expr.c (convert_modes): Added support for any size int.
	(emit_group_load_1): Added todo for place that still does not
	allow large ints.
	(store_expr, expand_constructor): Fixed comments.
	(expand_expr_real_2, expand_expr_real_1,
	reduce_to_bit_field_precision, const_vector_from_tree):
	Converted to use wide-int api.
	* optabs.c (expand_subword_shift, expand_doubleword_shift,
	expand_absneg_bit, expand_absneg_bit, expand_copysign_absneg,
	expand_copysign_bit): Made to work with any size int.  
	* cfgexpand.c (expand_debug_locations):  Use CONST_SCALAR_INT_P.
	* ggc.h (ggc_alloc_hwivec_sized): New.
 

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix
  2012-10-03 17:17 patch to fix Kenneth Zadeck
@ 2012-10-03 20:47 ` Marc Glisse
  2012-10-03 22:05   ` Kenneth Zadeck
  2012-10-03 22:55   ` Mike Stump
  2012-10-04 12:48 ` Richard Guenther
  1 sibling, 2 replies; 217+ messages in thread
From: Marc Glisse @ 2012-10-03 20:47 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, Richard Sandiford, gcc-patches

On Wed, 3 Oct 2012, Kenneth Zadeck wrote:

> The patch defines a new datatype, a 'wide_int' (defined in
> wide-int.[ch], and this datatype will be used to perform all of the
> integer constant math in the compiler.  Externally, wide-int is very
> similar to double-int except that it does not have the limitation that
> math must be done on exactly two HOST_WIDE_INTs.
>
> Internally, a wide_int is a structure that contains a fixed sized
> array of HOST_WIDE_INTs, a length field and a mode.  The size of the
> array is determined at generation time by dividing the number of bits
> of the largest integer supported on the target by the number of bits
> in a HOST_WIDE_INT of the host.  Thus, with this format, any length of
> integer can be supported on any host.

Hello,

did you consider making the size of wide_int a template parameter, now 
that we are using C++? All with a convenient typedef or macro so it 
doesn't show. I am asking because in vrp I do some arithmetic that 
requires 2*N+1 bits where N is the size of double_int.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix
  2012-10-03 20:47 ` Marc Glisse
@ 2012-10-03 22:05   ` Kenneth Zadeck
  2012-10-04 13:17     ` Marc Glisse
  2012-10-04 21:06     ` Marc Glisse
  2012-10-03 22:55   ` Mike Stump
  1 sibling, 2 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-03 22:05 UTC (permalink / raw)
  To: gcc-patches; +Cc: Marc Glisse, Mike Stump, Richard Sandiford

i have already converted the vrp code, so i have some guess at where you 
are talking about.  (of course correct me if i am wrong).

in the code that computes the range when two variables are multiplied 
together needs to do a multiplication that produces a result that is 
twice as wide as the inputs.

my library is able to do that with one catch (and this is a big catch): 
the target has to have an integer mode that is twice as big as the mode 
of the operands. The issue is that wide-ints actually carry around the 
mode of the value in order to get the bitsize and precision of the 
operands (it does not have the type, because this code has to both work 
on the rtl and tree level and i generally do not want the signness anyway).

my current code in vrp checks to see if such a mode exists and if it 
does, it produces the product.   if the mode does not exist, it returns 
bottom.   What this means is that for most (many or some) targets that 
have a TImode, the largest thing that particular vrp discover ranges for 
is a DImode value.   We could get around this by defining the next 
larger mode than what the target really needs but i wonder how much 
mileage you are going to get out of that with really large numbers.

Of course you could have something else in mind.

kenny

On 10/03/2012 04:47 PM, Marc Glisse wrote:
> On Wed, 3 Oct 2012, Kenneth Zadeck wrote:
>
>> The patch defines a new datatype, a 'wide_int' (defined in
>> wide-int.[ch], and this datatype will be used to perform all of the
>> integer constant math in the compiler.  Externally, wide-int is very
>> similar to double-int except that it does not have the limitation that
>> math must be done on exactly two HOST_WIDE_INTs.
>>
>> Internally, a wide_int is a structure that contains a fixed sized
>> array of HOST_WIDE_INTs, a length field and a mode.  The size of the
>> array is determined at generation time by dividing the number of bits
>> of the largest integer supported on the target by the number of bits
>> in a HOST_WIDE_INT of the host.  Thus, with this format, any length of
>> integer can be supported on any host.
>
> Hello,
>
> did you consider making the size of wide_int a template parameter, now 
> that we are using C++? All with a convenient typedef or macro so it 
> doesn't show. I am asking because in vrp I do some arithmetic that 
> requires 2*N+1 bits where N is the size of double_int.
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix
  2012-10-03 20:47 ` Marc Glisse
  2012-10-03 22:05   ` Kenneth Zadeck
@ 2012-10-03 22:55   ` Mike Stump
  1 sibling, 0 replies; 217+ messages in thread
From: Mike Stump @ 2012-10-03 22:55 UTC (permalink / raw)
  To: gcc-patches; +Cc: Kenneth Zadeck, Richard Sandiford

On Oct 3, 2012, at 1:47 PM, Marc Glisse <marc.glisse@inria.fr> wrote:
> did you consider making the size of wide_int a template parameter, now that we are using C++? All with a convenient typedef or macro so it doesn't show. I am asking because in vrp I do some arithmetic that requires 2*N+1 bits where N is the size of double_int.

No, not really.  I'd maybe answer it this way, we put in a type (singular) to support all integral constants in all languages on a port.  Since we only needed 1, there was little need to templatize it.  By supporting all integral constants in all languages, there is little need for more.  If Ada say, wanted a 2048 bit integer, then, we just have it drop off the size it wants someplace and we would mix that in on a MAX(….) line, net result, the type we use would then directly support the needs of Ada.  If vpr wanted 2x of all existing modes, we could simply change the MAX equation and essentially double it; if people need that.  This comes as a cost, as the intermediate wide values are fixed size allocated (not variable); so these all would be larger.  For the longer lived values, no change, as these are variably sized as one would expect.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix
  2012-10-03 17:17 patch to fix Kenneth Zadeck
  2012-10-03 20:47 ` Marc Glisse
@ 2012-10-04 12:48 ` Richard Guenther
  2012-10-04 13:55   ` patch to fix constant math Kenneth Zadeck
  2012-10-04 15:39   ` patch to fix Kenneth Zadeck
  1 sibling, 2 replies; 217+ messages in thread
From: Richard Guenther @ 2012-10-04 12:48 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, Richard Sandiford, gcc-patches

On Wed, Oct 3, 2012 at 7:15 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> The enclosed patch is the third of at least four patches that fix the
> problems associated with supporting integers on the target that are
> wider than two HOST_WIDE_INTs.
>
> While GCC claims to support OI mode, and we have two public ports that
> make minor use of this mode, in practice, compilation that uses OImode
> mode commonly gives the wrong result or ices.  We have a private port
> of GCC for an architecture that is further down the road to needing
> comprehensive OImode and we have discovered that this is unusable. We
> have decided to fix it in a general way that so that it is most
> beneficial to the GCC community.  It is our belief that we are just a
> little ahead of the X86 and the NEON and these patches will shortly be
> essential.
>
> The first two of these patches were primarily lexigraphical and have
> already been committed.    They transformed the uses of CONST_DOUBLE
> so that it is easy to tell what the intended usage is.
>
> The underlying structures in the next two patches are very general:
> once they are added to the compiler, the compiler will be able to
> support targets with any size of integer from hosts of any size
> integer.
>
> The patch enclosed deals with the portable RTL parts of the compiler.
> The next patch, which is currently under construction deals with the
> tree level.  However, this patch can be put on the trunk as is, and it
> will eleviate many, but not all of the current limitations in the rtl
> parts of the compiler.
>
> Some of the patch is conditional, depending on a port defining the
> symbol 'TARGET_SUPPORTS_WIDE_INT' to be non zero.  Defining this
> symbol to be non zero is declaring that the port has been converted to
> use the new form or integer constants.  However, the patch is
> completely backwards compatible to allow ports that do not need this
> immediately to convert at their leasure.  The conversion process is
> not difficult, but it does require some knowledge of the port, so we
> are not volinteering to do this for all ports.
>
> OVERVIEW OF THE PATCH:
>
> The patch defines a new datatype, a 'wide_int' (defined in
> wide-int.[ch], and this datatype will be used to perform all of the
> integer constant math in the compiler.  Externally, wide-int is very
> similar to double-int except that it does not have the limitation that
> math must be done on exactly two HOST_WIDE_INTs.
>
> Internally, a wide_int is a structure that contains a fixed sized
> array of HOST_WIDE_INTs, a length field and a mode.  The size of the

That it has a mode sounds odd to me and makes it subtly different
from HOST_WIDE_INT and double-int.  Maybe the patch will tell
why this is so.

> array is determined at generation time by dividing the number of bits
> of the largest integer supported on the target by the number of bits
> in a HOST_WIDE_INT of the host.  Thus, with this format, any length of
> integer can be supported on any host.
>
> A new rtx type is created, the CONST_WIDE_INT, which contains a
> garbage collected array of HOST_WIDE_INTS that is large enough to hold
> the constant.  For the targets that define TARGET_SUPPORTS_WIDE_INT to
> be non zero, CONST_DOUBLES are only used to hold floating point
> values.  If the target leaves TARGET_SUPPORTS_WIDE_INT defined as 0,
> CONST_WIDE_INTs are not used and CONST_DOUBLEs are as they were
> before.
>
> CONST_INT does not change except that it is defined to hold all
> constants that fit in exactly one HOST_WIDE_INT.  Note that is slightly
> different than the current trunk.  Before this patch, the TImode
> constant '5' could either be in a CONST_INT or CONST_DOUBLE depending
> on which code path was used to create it.  This patch changes this so
> that if the constant fits in a CONST_INT then it is represented in a
> CONST_INT no matter how it is created.
>
> For the array inside a CONST_WIDE_INT, and internally in wide-int, we
> use a compressed form for integers that need more than one
> HOST_WIDE_INT.  Higher elements of the array are not needed if they
> are just a sign extension of the elements below them.  This does not
> imply that constants are signed or are sign extended, this is only a
> compression technique.
>
> While it might seem to be more esthetically pleasing to have not
> introduced the CONST_WIDE_INT and to have changed the representation
> of the CONST_INT to accomodate larger numbers, this would have both
> used more space and would be a time consuming change for the port
> maintainers.  We believe that most ports can be quickly converted with
> the current scheme because there is just not a lot of code in the back
> ends that cares about large constants.  Furthermore, the CONST_INT is
> very space efficient and even in a program that was heavy in large
> values, most constants would still fit in a CONST_INT.
>
> All of the parts of the rtl level that deal with CONST_DOUBLE as an
> now conditionally work with CONST_WIDE_INTs depending on the value
> of TARGET_SUPPORTS_WIDE_INT.  We believe that this patch removes all
> of the ices and wrong code places at the portable rtl level. However,
> there are still places in the portable rtl code that refuse to
> transform the code unless it is a CONST_INT.  Since these do not cause
> failures, they can be handled later.  The patch is already very large.
>
> It should be noted that much of the constant overflow checking in the
> constant math dissappears with these patches.  The overflow checking
> code in the current compiler is really divided into two cases:
> overflow on the host and overflow on the target.  The overflow
> checking on the host was to make sure that the math did overflow when
> done on two HOST_WIDE_INTs.  All of this code goes away.  These
> patches allow the constant math to be done exactly the way it is done
> on the target.
>
> This patch also aids other cleanups that are being considered at the
> rtl level:
>
>   1) These patches remove most of the host dependencies on the
>   optimizations.  Currently a 32 bit GCC host will produce different
>   code for a specific target than a 64 bit host will.  This is because
>   many of the transformations only work on constants that can be a
>   represented with a single HWI or two HWIs.  If the target has larger
>   integers than the host, the compilation suffers.
>
>   2) Bernd's need to make GCC correctly support partial its is made
>   easier by the wide-int library.  This library carefully does all
>   arithmetic in the precision of the mode included in it.  While there
>   are still places at the rtl level that still do arithmetic inline,
>   we plan to convert those to use the library over time.   This patch
>   converts a substantial number of those places.
>
>   3) This patch is one step along the path to add modes to rtl integer
>   constants.  There is no longer any checking to see if a CONST_DOUBLE
>   has VOIDmode as its mode.  Furthermore, all constructors for various
>   wide ints do take a mode and require that it not be VOIDmode. There
>   is still a lot of work to do to make this conversion possible.
>
> Richard Sandiford has been over the rtl portions of this patch a few
> times.  He has not looked at the wide-int files in any detail.  This
> patch has been heavily tested on my private ports and also on x86-64.
>
>
> CONVERSION PROCESS
>
> Converting a port mostly requires looking for the places where
> CONST_DOUBLES are used with VOIDmode and replacing that code with code
> that accesses CONST_WIDE_INTs.  "grep -i const_double" at the port
> level gets you to 95% of the changes that need to be made.  There are
> a few places that require a deeper look.
>
>   1) There is no equivalent to hval and lval for CONST_WIDE_INTs.
>   This would be difficult to express in the md language since there
>   are a variable number of elements.
>
>   Most ports only check that hval is either 0 or -1 to see if the int
>   is small.  As mentioned above, this will no longer be necessary
>   since small constants are always CONST_INT.  Of course there are
>   still a few exceptions, the alpha's constraint used by the zap
>   instruction certainly requires careful examination by C code.
>   However, all the current code does is pass the hval and lval to C
>   code, so evolving the c code to look at the CONST_WIDE_INT is not
>   really a large change.
>
>   2) Because there is no standard template that ports use to
>   materialize constants, there is likely to be some futzing that is
>   unique to each port in this code.
>
>   3) The rtx costs may have to be adjusted to properly account for
>   larger constants that are represented as CONST_WIDE_INT.
>
> All and all it has not taken us long to convert ports that we are
> familiar with.
>
> OTHER COMMENTS
>
> I did find what i believe is one interesting bug in the double-int
> code.  I believe that the code that performs divide and mod with round
> to nearest is seriously wrong for unsigned integers.  I believe that
> it will get the wrong answer for any numbers that are large enough to
> look negative if they consider signed integers.  Asside from that,
> wide-int should perform in a very similar manner to double-int.
>
> I am sorry for the size of this patch.   However, there does not appear
> to change the underlying data structure to support wider integers
> without doing something like this.

Some pieces can be easily split out, like the introduction and use
of CONST_SCALAR_INT_P.

As my general comment I would like to see double-int and wide-int
unified from an interface perspective.  Which means that double-int
should be a specialization of wide-int which should be a template
(which also means its size is constant).  Thus,

typedef wide_int<2> double_int;

should be the way to expose the double_int type.

The main question remains - why does wide_int have a mode?
That looks redundant, both with information stored in types
and the RTL constant, and with the len field (that would be
always GET_MODE_SIZE () / ...?).  Also when you associate
a mode it's weird you don't associate a signedness.

Thus I'd ask you to rework this to be a template on 'len'
(number of HOST_WIDE_INT words), drop the mode member
and unify double-int and wide-int.  Co-incidentially incrementally
doing this by converting double-int to a typedef of a
wide_int<2> specialization (thus moving double-int implementation
stuff to be wide_int<2> specialized) would be prefered.

Btw,

+/* Constructs tree in type TYPE from with value given by CST.  Signedness
+   of CST is assumed to be the same as the signedness of TYPE.  */
+
+tree
+wide_int_to_tree (tree type, const wide_int &cst)
+{
+  wide_int v;
+  if (TYPE_UNSIGNED (type))
+    v = cst.zext (TYPE_PRECISION (type));
+  else
+    v = cst.sext (TYPE_PRECISION (type));
+
+  return build_int_cst_wide (type, v.elt (0), v.elt (1));
+}

is surely broken.  A wide-int does not fit a double-int.  How are you
going to "fix" this?

Thanks,
Richard.

> kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix
  2012-10-03 22:05   ` Kenneth Zadeck
@ 2012-10-04 13:17     ` Marc Glisse
  2012-10-04 15:19       ` Kenneth Zadeck
  2012-10-04 21:06     ` Marc Glisse
  1 sibling, 1 reply; 217+ messages in thread
From: Marc Glisse @ 2012-10-04 13:17 UTC (permalink / raw)
  To: Mike Stump, Kenneth Zadeck; +Cc: gcc-patches, Richard Sandiford

On Wed, 3 Oct 2012, Mike Stump wrote:
> On Oct 3, 2012, at 1:47 PM, Marc Glisse <marc.glisse@inria.fr> wrote:
>> did you consider making the size of wide_int a template parameter, now 
>> that we are using C++? All with a convenient typedef or macro so it 
>> doesn't show. I am asking because in vrp I do some arithmetic that 
>> requires 2*N+1 bits where N is the size of double_int.
>
> No, not really.  I'd maybe answer it this way, we put in a type 
> (singular) to support all integral constants in all languages on a port. 
> Since we only needed 1, there was little need to templatize it.  By 
> supporting all integral constants in all languages, there is little need 
> for more.  If Ada say, wanted a 2048 bit integer, then, we just have it 
> drop off the size it wants someplace and we would mix that in on a 
> MAX(….) line, net result, the type we use would then directly support 
> the needs of Ada.  If vpr wanted 2x of all existing modes, we could 
> simply change the MAX equation and essentially double it; if people need 
> that.  This comes as a cost, as the intermediate wide values are fixed 
> size allocated (not variable); so these all would be larger.

And this cost could be eliminated by having a template wide_int_ so only 
the places that need it actually use the extra size ;-)


On Wed, 3 Oct 2012, Kenneth Zadeck wrote:

> i have already converted the vrp code, so i have some guess at where you are 
> talking about.  (of course correct me if i am wrong).
>
> in the code that computes the range when two variables are multiplied 
> together needs to do a multiplication that produces a result that is twice as 
> wide as the inputs.

Yes, exactly.

> my library is able to do that with one catch (and this is a big catch): the 
> target has to have an integer mode that is twice as big as the mode of the 
> operands. The issue is that wide-ints actually carry around the mode of the 
> value in order to get the bitsize and precision of the operands (it does not 
> have the type, because this code has to both work on the rtl and tree level 
> and i generally do not want the signness anyway).
>
> my current code in vrp checks to see if such a mode exists and if it does, it 
> produces the product.   if the mode does not exist, it returns bottom.   What 
> this means is that for most (many or some) targets that have a TImode, the 
> largest thing that particular vrp discover ranges for is a DImode value.   We 
> could get around this by defining the next larger mode than what the target 
> really needs but i wonder how much mileage you are going to get out of that 
> with really large numbers.

This will be for discussion when you submit that next patch, but currently 
VRP handles integers the same size as double_int. In particular, it 
handles __int128. I would be unhappy if introducing a larger bigint type 
in gcc made us regress there.


-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-04 12:48 ` Richard Guenther
@ 2012-10-04 13:55   ` Kenneth Zadeck
  2012-10-04 16:58     ` Richard Guenther
  2012-10-04 15:39   ` patch to fix Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-04 13:55 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Mike Stump, Richard Sandiford, gcc-patches

Let me talk about the mode here first.

What this interface/patch provides is a facility where the constant math 
that is done in optimizations is done exactly the way that it would be 
done on the target machine.   What we have now is a compiler that only 
does this if it convenient to do on the host.   I admit that i care 
about this more than others right now, but if intel adds a couple of 
more instructions to their vector units, other people will start to 
really care about this issue.   If you take an OImode value with the 
current compiler and left shift it by 250 the middle end will say that 
the result is 0.   This is just wrong!!!

What this means is that the bitsize and precision of the operations need 
to be carried along when doing math. when wide-int  checks for overflow 
on the multiply or add, it is not checking the if the value overflowed 
on two HWIs, it is checking if the add overflowed in the mode of the 
types that are represented on the target.   When we do shift, we are not 
doing a shift within two HWIs, we are truncating the shift value (if 
this is appropriate) according to the bitsize and shifting according the 
precision.

I think that an argument could be made that storing the mode should be 
changed to an explicit precision and bitsize.  (A possible other option 
would be to store a tree type, but this would make the usage at the rtl 
level very cumbersome since types are rare.) Aside from the work, you 
would not get much push back.

But the signess is a different argument.   At the rtl level, the signess 
is a matter of context.   (you could argue that this is a mistake and i 
would agree, but that is an even bigger change.)   But more to the 
point, at the tree level, there are a surprising number of places where 
the operation desired does not follow the sign of the types that were 
used to construct the constants.   Furthermore, not carrying the sign is 
more consistent with the double int code, which as you point out carries 
nothing.

As for the splitting out the patch in smaller pieces, i am all for it.   
I have done this twice already and i could get the const_scalar_int_p 
patch out quickly.    But you do not get too far along that before you 
are still left with a big patch.   I could split out wide-int.* and just 
commit those files with no clients as a first step.   My guess is that 
Richard Sandiford would appreciate that because while he has carefully 
checked the rtl stuff, i think that the code inside wide-int is not in 
his comfort zone of things he would approve.

As far as your btw - noticed this last night.   it is an artifact of the 
way i produced the patch and "responsible people have been sacked".   
However, it shows that you read the patch carefully, and i really 
appreciate that.   i owe you a beer (not that you need another at this 
time of year).

Kenny



On 10/04/2012 08:48 AM, Richard Guenther wrote:
> On Wed, Oct 3, 2012 at 7:15 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> The enclosed patch is the third of at least four patches that fix the
>> problems associated with supporting integers on the target that are
>> wider than two HOST_WIDE_INTs.
>>
>> While GCC claims to support OI mode, and we have two public ports that
>> make minor use of this mode, in practice, compilation that uses OImode
>> mode commonly gives the wrong result or ices.  We have a private port
>> of GCC for an architecture that is further down the road to needing
>> comprehensive OImode and we have discovered that this is unusable. We
>> have decided to fix it in a general way that so that it is most
>> beneficial to the GCC community.  It is our belief that we are just a
>> little ahead of the X86 and the NEON and these patches will shortly be
>> essential.
>>
>> The first two of these patches were primarily lexigraphical and have
>> already been committed.    They transformed the uses of CONST_DOUBLE
>> so that it is easy to tell what the intended usage is.
>>
>> The underlying structures in the next two patches are very general:
>> once they are added to the compiler, the compiler will be able to
>> support targets with any size of integer from hosts of any size
>> integer.
>>
>> The patch enclosed deals with the portable RTL parts of the compiler.
>> The next patch, which is currently under construction deals with the
>> tree level.  However, this patch can be put on the trunk as is, and it
>> will eleviate many, but not all of the current limitations in the rtl
>> parts of the compiler.
>>
>> Some of the patch is conditional, depending on a port defining the
>> symbol 'TARGET_SUPPORTS_WIDE_INT' to be non zero.  Defining this
>> symbol to be non zero is declaring that the port has been converted to
>> use the new form or integer constants.  However, the patch is
>> completely backwards compatible to allow ports that do not need this
>> immediately to convert at their leasure.  The conversion process is
>> not difficult, but it does require some knowledge of the port, so we
>> are not volinteering to do this for all ports.
>>
>> OVERVIEW OF THE PATCH:
>>
>> The patch defines a new datatype, a 'wide_int' (defined in
>> wide-int.[ch], and this datatype will be used to perform all of the
>> integer constant math in the compiler.  Externally, wide-int is very
>> similar to double-int except that it does not have the limitation that
>> math must be done on exactly two HOST_WIDE_INTs.
>>
>> Internally, a wide_int is a structure that contains a fixed sized
>> array of HOST_WIDE_INTs, a length field and a mode.  The size of the
> That it has a mode sounds odd to me and makes it subtly different
> from HOST_WIDE_INT and double-int.  Maybe the patch will tell
> why this is so.
>
>> array is determined at generation time by dividing the number of bits
>> of the largest integer supported on the target by the number of bits
>> in a HOST_WIDE_INT of the host.  Thus, with this format, any length of
>> integer can be supported on any host.
>>
>> A new rtx type is created, the CONST_WIDE_INT, which contains a
>> garbage collected array of HOST_WIDE_INTS that is large enough to hold
>> the constant.  For the targets that define TARGET_SUPPORTS_WIDE_INT to
>> be non zero, CONST_DOUBLES are only used to hold floating point
>> values.  If the target leaves TARGET_SUPPORTS_WIDE_INT defined as 0,
>> CONST_WIDE_INTs are not used and CONST_DOUBLEs are as they were
>> before.
>>
>> CONST_INT does not change except that it is defined to hold all
>> constants that fit in exactly one HOST_WIDE_INT.  Note that is slightly
>> different than the current trunk.  Before this patch, the TImode
>> constant '5' could either be in a CONST_INT or CONST_DOUBLE depending
>> on which code path was used to create it.  This patch changes this so
>> that if the constant fits in a CONST_INT then it is represented in a
>> CONST_INT no matter how it is created.
>>
>> For the array inside a CONST_WIDE_INT, and internally in wide-int, we
>> use a compressed form for integers that need more than one
>> HOST_WIDE_INT.  Higher elements of the array are not needed if they
>> are just a sign extension of the elements below them.  This does not
>> imply that constants are signed or are sign extended, this is only a
>> compression technique.
>>
>> While it might seem to be more esthetically pleasing to have not
>> introduced the CONST_WIDE_INT and to have changed the representation
>> of the CONST_INT to accomodate larger numbers, this would have both
>> used more space and would be a time consuming change for the port
>> maintainers.  We believe that most ports can be quickly converted with
>> the current scheme because there is just not a lot of code in the back
>> ends that cares about large constants.  Furthermore, the CONST_INT is
>> very space efficient and even in a program that was heavy in large
>> values, most constants would still fit in a CONST_INT.
>>
>> All of the parts of the rtl level that deal with CONST_DOUBLE as an
>> now conditionally work with CONST_WIDE_INTs depending on the value
>> of TARGET_SUPPORTS_WIDE_INT.  We believe that this patch removes all
>> of the ices and wrong code places at the portable rtl level. However,
>> there are still places in the portable rtl code that refuse to
>> transform the code unless it is a CONST_INT.  Since these do not cause
>> failures, they can be handled later.  The patch is already very large.
>>
>> It should be noted that much of the constant overflow checking in the
>> constant math dissappears with these patches.  The overflow checking
>> code in the current compiler is really divided into two cases:
>> overflow on the host and overflow on the target.  The overflow
>> checking on the host was to make sure that the math did overflow when
>> done on two HOST_WIDE_INTs.  All of this code goes away.  These
>> patches allow the constant math to be done exactly the way it is done
>> on the target.
>>
>> This patch also aids other cleanups that are being considered at the
>> rtl level:
>>
>>    1) These patches remove most of the host dependencies on the
>>    optimizations.  Currently a 32 bit GCC host will produce different
>>    code for a specific target than a 64 bit host will.  This is because
>>    many of the transformations only work on constants that can be a
>>    represented with a single HWI or two HWIs.  If the target has larger
>>    integers than the host, the compilation suffers.
>>
>>    2) Bernd's need to make GCC correctly support partial its is made
>>    easier by the wide-int library.  This library carefully does all
>>    arithmetic in the precision of the mode included in it.  While there
>>    are still places at the rtl level that still do arithmetic inline,
>>    we plan to convert those to use the library over time.   This patch
>>    converts a substantial number of those places.
>>
>>    3) This patch is one step along the path to add modes to rtl integer
>>    constants.  There is no longer any checking to see if a CONST_DOUBLE
>>    has VOIDmode as its mode.  Furthermore, all constructors for various
>>    wide ints do take a mode and require that it not be VOIDmode. There
>>    is still a lot of work to do to make this conversion possible.
>>
>> Richard Sandiford has been over the rtl portions of this patch a few
>> times.  He has not looked at the wide-int files in any detail.  This
>> patch has been heavily tested on my private ports and also on x86-64.
>>
>>
>> CONVERSION PROCESS
>>
>> Converting a port mostly requires looking for the places where
>> CONST_DOUBLES are used with VOIDmode and replacing that code with code
>> that accesses CONST_WIDE_INTs.  "grep -i const_double" at the port
>> level gets you to 95% of the changes that need to be made.  There are
>> a few places that require a deeper look.
>>
>>    1) There is no equivalent to hval and lval for CONST_WIDE_INTs.
>>    This would be difficult to express in the md language since there
>>    are a variable number of elements.
>>
>>    Most ports only check that hval is either 0 or -1 to see if the int
>>    is small.  As mentioned above, this will no longer be necessary
>>    since small constants are always CONST_INT.  Of course there are
>>    still a few exceptions, the alpha's constraint used by the zap
>>    instruction certainly requires careful examination by C code.
>>    However, all the current code does is pass the hval and lval to C
>>    code, so evolving the c code to look at the CONST_WIDE_INT is not
>>    really a large change.
>>
>>    2) Because there is no standard template that ports use to
>>    materialize constants, there is likely to be some futzing that is
>>    unique to each port in this code.
>>
>>    3) The rtx costs may have to be adjusted to properly account for
>>    larger constants that are represented as CONST_WIDE_INT.
>>
>> All and all it has not taken us long to convert ports that we are
>> familiar with.
>>
>> OTHER COMMENTS
>>
>> I did find what i believe is one interesting bug in the double-int
>> code.  I believe that the code that performs divide and mod with round
>> to nearest is seriously wrong for unsigned integers.  I believe that
>> it will get the wrong answer for any numbers that are large enough to
>> look negative if they consider signed integers.  Asside from that,
>> wide-int should perform in a very similar manner to double-int.
>>
>> I am sorry for the size of this patch.   However, there does not appear
>> to change the underlying data structure to support wider integers
>> without doing something like this.
> Some pieces can be easily split out, like the introduction and use
> of CONST_SCALAR_INT_P.
>
> As my general comment I would like to see double-int and wide-int
> unified from an interface perspective.  Which means that double-int
> should be a specialization of wide-int which should be a template
> (which also means its size is constant).  Thus,
>
> typedef wide_int<2> double_int;
>
> should be the way to expose the double_int type.
>
> The main question remains - why does wide_int have a mode?
> That looks redundant, both with information stored in types
> and the RTL constant, and with the len field (that would be
> always GET_MODE_SIZE () / ...?).  Also when you associate
> a mode it's weird you don't associate a signedness.
>
> Thus I'd ask you to rework this to be a template on 'len'
> (number of HOST_WIDE_INT words), drop the mode member
> and unify double-int and wide-int.  Co-incidentially incrementally
> doing this by converting double-int to a typedef of a
> wide_int<2> specialization (thus moving double-int implementation
> stuff to be wide_int<2> specialized) would be prefered.
>
> Btw,
>
> +/* Constructs tree in type TYPE from with value given by CST.  Signedness
> +   of CST is assumed to be the same as the signedness of TYPE.  */
> +
> +tree
> +wide_int_to_tree (tree type, const wide_int &cst)
> +{
> +  wide_int v;
> +  if (TYPE_UNSIGNED (type))
> +    v = cst.zext (TYPE_PRECISION (type));
> +  else
> +    v = cst.sext (TYPE_PRECISION (type));
> +
> +  return build_int_cst_wide (type, v.elt (0), v.elt (1));
> +}
>
> is surely broken.  A wide-int does not fit a double-int.  How are you
> going to "fix" this?
>
> Thanks,
> Richard.
>
>> kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix
  2012-10-04 13:17     ` Marc Glisse
@ 2012-10-04 15:19       ` Kenneth Zadeck
  2012-10-04 16:55         ` Marc Glisse
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-04 15:19 UTC (permalink / raw)
  To: Marc Glisse; +Cc: Mike Stump, gcc-patches, Richard Sandiford

On 10/04/2012 09:17 AM, Marc Glisse wrote:
> On Wed, 3 Oct 2012, Mike Stump wrote:
>> On Oct 3, 2012, at 1:47 PM, Marc Glisse <marc.glisse@inria.fr> wrote:
>>> did you consider making the size of wide_int a template parameter, 
>>> now that we are using C++? All with a convenient typedef or macro so 
>>> it doesn't show. I am asking because in vrp I do some arithmetic 
>>> that requires 2*N+1 bits where N is the size of double_int.
>>
>> No, not really.  I'd maybe answer it this way, we put in a type 
>> (singular) to support all integral constants in all languages on a 
>> port. Since we only needed 1, there was little need to templatize 
>> it.  By supporting all integral constants in all languages, there is 
>> little need for more.  If Ada say, wanted a 2048 bit integer, then, 
>> we just have it drop off the size it wants someplace and we would mix 
>> that in on a MAX(….) line, net result, the type we use would then 
>> directly support the needs of Ada.  If vpr wanted 2x of all existing 
>> modes, we could simply change the MAX equation and essentially double 
>> it; if people need that.  This comes as a cost, as the intermediate 
>> wide values are fixed size allocated (not variable); so these all 
>> would be larger.
>
> And this cost could be eliminated by having a template wide_int_ so 
> only the places that need it actually use the extra size ;-)
>
The space is not really an issue in most places since wide-ints tend to 
be short lived.  i guess vrp is slightly different because it creates a 
lot at once.  but then they go away.

However the real question is what are you going to instantiate the 
template on?    What we do is look at the target and determine the 
largest type that the target supports and build a wide int type that 
supports that.    how are you going to do better?   are you going to 
instantiate one for every type you see?   are these going to be static 
or dynamic?   The last line this email seems to imply that you were 
planning to "know" that __int128 was the largest integer that any target 
or front end could support.

and then what do you do for the parts of the compiler that have 
operations that take things of two different types, like shift. The 
shift amount can and may times is a shorter type that what is being 
shifted. Would these different length integers be represented with 
different instances from the same template?   I am not a c++ programmer 
and so all of this is a little new to me, but given a perspective of the 
rest of the compiler, this does not seem like the right way to go.


>
> On Wed, 3 Oct 2012, Kenneth Zadeck wrote:
>
>> i have already converted the vrp code, so i have some guess at where 
>> you are talking about.  (of course correct me if i am wrong).
>>
>> in the code that computes the range when two variables are multiplied 
>> together needs to do a multiplication that produces a result that is 
>> twice as wide as the inputs.
>
> Yes, exactly.
>
>> my library is able to do that with one catch (and this is a big 
>> catch): the target has to have an integer mode that is twice as big 
>> as the mode of the operands. The issue is that wide-ints actually 
>> carry around the mode of the value in order to get the bitsize and 
>> precision of the operands (it does not have the type, because this 
>> code has to both work on the rtl and tree level and i generally do 
>> not want the signness anyway).
>>
>> my current code in vrp checks to see if such a mode exists and if it 
>> does, it produces the product.   if the mode does not exist, it 
>> returns bottom.   What this means is that for most (many or some) 
>> targets that have a TImode, the largest thing that particular vrp 
>> discover ranges for is a DImode value.   We could get around this by 
>> defining the next larger mode than what the target really needs but i 
>> wonder how much mileage you are going to get out of that with really 
>> large numbers.
>
> This will be for discussion when you submit that next patch, but 
> currently VRP handles integers the same size as double_int. In 
> particular, it handles __int128. I would be unhappy if introducing a 
> larger bigint type in gcc made us regress there.
>
You are only happy now because you do not really understand the world 
around you.    This is not what your code does.   What you code does is 
that if the host is a 64 bit host you can handle __int128 and if your 
host is a 32 bit host you can handle a __int64.  If you are building a 
cross compiler from a 32 bit host to a 64 bit target, your pass is 
either going to get the wrong answer, give up, or ice.   There are 
currently parts of gcc that do each of these three "solutions" and my 
patch gets rid of these because it does the math as the target does the 
math, no matter that the target is.

The goal of my patch is to make gcc produce the same correct results no 
matter what types the target or host support.    The last thing that we 
need to have some optimization "knowing" what the limits of either of 
these are and hard coding that in a set of templates that have been 
statically instantiated.


^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix
  2012-10-04 12:48 ` Richard Guenther
  2012-10-04 13:55   ` patch to fix constant math Kenneth Zadeck
@ 2012-10-04 15:39   ` Kenneth Zadeck
  1 sibling, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-04 15:39 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Mike Stump, Richard Sandiford, gcc-patches

Actually richi, this code is "correct" for some broken definition of 
correct.

If all that is done is to convert the rtl parts of the compiler, then 
this code is the best you can do (of course an assertion that the length 
is not greater than 2 would be a useful addition).

The code that is in the follow on patch which converts the insides of a 
tree cst to look like a const wide int, i.e. an array of HWIs.   When 
that happens, this code looks completely different. But if you only 
convert the rtl level, at some point there is going to be an impedance 
mismatch and it is buried here.

I will point out that this is the fall out of trying to split things 
into a bunch of smaller patches that could in theory go in separately.

kenny




>
> +/* Constructs tree in type TYPE from with value given by CST.  Signedness
> +   of CST is assumed to be the same as the signedness of TYPE.  */
> +
> +tree
> +wide_int_to_tree (tree type, const wide_int &cst)
> +{
> +  wide_int v;
> +  if (TYPE_UNSIGNED (type))
> +    v = cst.zext (TYPE_PRECISION (type));
> +  else
> +    v = cst.sext (TYPE_PRECISION (type));
> +
> +  return build_int_cst_wide (type, v.elt (0), v.elt (1));
> +}
>
> is surely broken.  A wide-int does not fit a double-int.  How are you
> going to "fix" this?
>
> Thanks,
> Richard.
>
>> kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix
  2012-10-04 15:19       ` Kenneth Zadeck
@ 2012-10-04 16:55         ` Marc Glisse
  0 siblings, 0 replies; 217+ messages in thread
From: Marc Glisse @ 2012-10-04 16:55 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, Richard Sandiford

On Thu, 4 Oct 2012, Kenneth Zadeck wrote:

> On 10/04/2012 09:17 AM, Marc Glisse wrote:
>> On Wed, 3 Oct 2012, Mike Stump wrote:
>>> On Oct 3, 2012, at 1:47 PM, Marc Glisse <marc.glisse@inria.fr> wrote:
>>>> did you consider making the size of wide_int a template parameter, now 
>>>> that we are using C++? All with a convenient typedef or macro so it 
>>>> doesn't show. I am asking because in vrp I do some arithmetic that 
>>>> requires 2*N+1 bits where N is the size of double_int.
>>> 
>>> No, not really.  I'd maybe answer it this way, we put in a type (singular) 
>>> to support all integral constants in all languages on a port. Since we 
>>> only needed 1, there was little need to templatize it.  By supporting all 
>>> integral constants in all languages, there is little need for more.  If 
>>> Ada say, wanted a 2048 bit integer, then, we just have it drop off the 
>>> size it wants someplace and we would mix that in on a MAX(….) line, net 
>>> result, the type we use would then directly support the needs of Ada.  If 
>>> vpr wanted 2x of all existing modes, we could simply change the MAX 
>>> equation and essentially double it; if people need that.  This comes as a 
>>> cost, as the intermediate wide values are fixed size allocated (not 
>>> variable); so these all would be larger.
>> 
>> And this cost could be eliminated by having a template wide_int_ so only 
>> the places that need it actually use the extra size ;-)
>> 
> The space is not really an issue in most places since wide-ints tend to be 
> short lived.

You were the one talking of a cost.

> However the real question is what are you going to instantiate the template 
> on?    What we do is look at the target and determine the largest type that 
> the target supports and build a wide int type that supports that.    how are 
> you going to do better?

In a single place in tree-vrp.c in the code that evaluates 
multiplications, I would instantiate the template on the double (possibly 
+1) of the value you selected as large enough for all constants. For all 
the rest, your type is fine.

>> This will be for discussion when you submit that next patch, but currently 
>> VRP handles integers the same size as double_int. In particular, it handles 
>> __int128. I would be unhappy if introducing a larger bigint type in gcc 
>> made us regress there.
>> 
> You are only happy now because you do not really understand the world around 
> you.

I did not want to go into details, but let me re-phrase: I do not want to 
regress. Currently, hosts with a 64 bit hwi can handle VRP multiplications 
on __int128. If your patch introducing better big integers breaks that, 
that sounds bad to me, since I would expect s/double_int/wide_int/ to just 
work, and using wide_int<2*MAX> would just be a potential simplification 
of the code for later.


Note that VRP is just the one case I am familiar with. Using templates 
should (I haven't checked) be completely trivial and help the next person 
who needs bigger integers for a specific purpose and doesn't want to 
penalize the whole compiler. If the size of wide_int is completely 
irrelevant and we can make it 10 times larger without thinking, I guess 
some numbers showing it would be great (or maybe that's common 
knowledge, then I guess it is fine).


Now those are only some comments from an occasional contributor, not 
reviewer requirements, it is fine to ignore them.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-04 13:55   ` patch to fix constant math Kenneth Zadeck
@ 2012-10-04 16:58     ` Richard Guenther
  2012-10-04 18:08       ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Guenther @ 2012-10-04 16:58 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, Richard Sandiford, gcc-patches

On Thu, Oct 4, 2012 at 3:55 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> Let me talk about the mode here first.
>
> What this interface/patch provides is a facility where the constant math
> that is done in optimizations is done exactly the way that it would be done
> on the target machine.   What we have now is a compiler that only does this
> if it convenient to do on the host.   I admit that i care about this more
> than others right now, but if intel adds a couple of more instructions to
> their vector units, other people will start to really care about this issue.
> If you take an OImode value with the current compiler and left shift it by
> 250 the middle end will say that the result is 0.   This is just wrong!!!
>
> What this means is that the bitsize and precision of the operations need to
> be carried along when doing math. when wide-int  checks for overflow on the
> multiply or add, it is not checking the if the value overflowed on two HWIs,
> it is checking if the add overflowed in the mode of the types that are
> represented on the target.   When we do shift, we are not doing a shift
> within two HWIs, we are truncating the shift value (if this is appropriate)
> according to the bitsize and shifting according the precision.
>
> I think that an argument could be made that storing the mode should be
> changed to an explicit precision and bitsize.  (A possible other option
> would be to store a tree type, but this would make the usage at the rtl
> level very cumbersome since types are rare.) Aside from the work, you would
> not get much push back.
>
> But the signess is a different argument.   At the rtl level, the signess is
> a matter of context.   (you could argue that this is a mistake and i would
> agree, but that is an even bigger change.)   But more to the point, at the
> tree level, there are a surprising number of places where the operation
> desired does not follow the sign of the types that were used to construct
> the constants.   Furthermore, not carrying the sign is more consistent with
> the double int code, which as you point out carries nothing.

Well, on RTL the signedness is on the operation (you have sdiv and udiv, etc.).

double-int tries to present a sign-less twos-complement entity of size
2 * HOST_BITS_PER_WIDE_INT.  I think that is sensible and for
obvious reasons should not change.  Both tree and RTL rely on this.
What we do not want is that up to TImode you get an internal representation
done one way (twos-complement) and on OImode and larger you
suddenly get subtly different behavior.  That's a recepie for desaster.

I'd like to clean up the interface to double-int some more (now with the
nice C++ stuff we have).  double-int should be pure twos-complement,
there should be no operations on double-ints that behave differently
when done signed or unsigned, instead we have signed and unsigned
versions of the operations (similar to how signedness is handled on
the RTL level).  With some trivial C++ fu you could have a
double_sint and double_uint type that would get rid of the bool
sign params we have to some functions (and then you could
write double_sint >> n using operator notation).

I'd like wide-int (whatever it's internal representation is) to behave
exactly like double-ints with respect to precision and signedness
handling.  Ideally all static functions we have that operate on
double-ints would be 1:1 available for wide-ints, so I can change
the type of entities in an algorithm from double-ints to wide-ints
(or vice versa) and do not have to change the code at all.

Thus as first step I'd like you to go over the double-int stuff,
compare it to the wide-int stuff you introduce and point out
differences (changing double-ints or wide-ints to whatever is
the more general concept).

Now, as for 'modes' - similar to signedness some functions
that operate on double-ints take a precision argument (like
the various extensions).  You can add a similar wrapper
type like double_sint, but this time with a cost - a new precision
member, that can be constructed from a double_int (or wide_int)
that ends up specifying the desired precision (be it in terms
of a mode or a type).

You didn't question my suggestion to have the number of
HOST_WIDE_INTs in a wide-int be compile-time constant - was
that just an oversight on your side?  The consequence is that
code wanting to deal with arbitrary length wide-ints needs to
be a template.

> As for the splitting out the patch in smaller pieces, i am all for it.   I
> have done this twice already and i could get the const_scalar_int_p patch
> out quickly.    But you do not get too far along that before you are still
> left with a big patch.   I could split out wide-int.* and just commit those
> files with no clients as a first step.   My guess is that Richard Sandiford
> would appreciate that because while he has carefully checked the rtl stuff,
> i think that the code inside wide-int is not in his comfort zone of things
> he would approve.
>
> As far as your btw - noticed this last night.   it is an artifact of the way
> i produced the patch and "responsible people have been sacked".   However,
> it shows that you read the patch carefully, and i really appreciate that.
> i owe you a beer (not that you need another at this time of year).

You also didn't mention the missing tree bits ... was this just a 1/n patch
or is it at all usable for you in this state?  Where do the large integers
magically come from?

Richard.

> Kenny
>
>
>
> On 10/04/2012 08:48 AM, Richard Guenther wrote:
>>
>> On Wed, Oct 3, 2012 at 7:15 PM, Kenneth Zadeck <zadeck@naturalbridge.com>
>> wrote:
>>>
>>> The enclosed patch is the third of at least four patches that fix the
>>> problems associated with supporting integers on the target that are
>>> wider than two HOST_WIDE_INTs.
>>>
>>> While GCC claims to support OI mode, and we have two public ports that
>>> make minor use of this mode, in practice, compilation that uses OImode
>>> mode commonly gives the wrong result or ices.  We have a private port
>>> of GCC for an architecture that is further down the road to needing
>>> comprehensive OImode and we have discovered that this is unusable. We
>>> have decided to fix it in a general way that so that it is most
>>> beneficial to the GCC community.  It is our belief that we are just a
>>> little ahead of the X86 and the NEON and these patches will shortly be
>>> essential.
>>>
>>> The first two of these patches were primarily lexigraphical and have
>>> already been committed.    They transformed the uses of CONST_DOUBLE
>>> so that it is easy to tell what the intended usage is.
>>>
>>> The underlying structures in the next two patches are very general:
>>> once they are added to the compiler, the compiler will be able to
>>> support targets with any size of integer from hosts of any size
>>> integer.
>>>
>>> The patch enclosed deals with the portable RTL parts of the compiler.
>>> The next patch, which is currently under construction deals with the
>>> tree level.  However, this patch can be put on the trunk as is, and it
>>> will eleviate many, but not all of the current limitations in the rtl
>>> parts of the compiler.
>>>
>>> Some of the patch is conditional, depending on a port defining the
>>> symbol 'TARGET_SUPPORTS_WIDE_INT' to be non zero.  Defining this
>>> symbol to be non zero is declaring that the port has been converted to
>>> use the new form or integer constants.  However, the patch is
>>> completely backwards compatible to allow ports that do not need this
>>> immediately to convert at their leasure.  The conversion process is
>>> not difficult, but it does require some knowledge of the port, so we
>>> are not volinteering to do this for all ports.
>>>
>>> OVERVIEW OF THE PATCH:
>>>
>>> The patch defines a new datatype, a 'wide_int' (defined in
>>> wide-int.[ch], and this datatype will be used to perform all of the
>>> integer constant math in the compiler.  Externally, wide-int is very
>>> similar to double-int except that it does not have the limitation that
>>> math must be done on exactly two HOST_WIDE_INTs.
>>>
>>> Internally, a wide_int is a structure that contains a fixed sized
>>> array of HOST_WIDE_INTs, a length field and a mode.  The size of the
>>
>> That it has a mode sounds odd to me and makes it subtly different
>> from HOST_WIDE_INT and double-int.  Maybe the patch will tell
>> why this is so.
>>
>>> array is determined at generation time by dividing the number of bits
>>> of the largest integer supported on the target by the number of bits
>>> in a HOST_WIDE_INT of the host.  Thus, with this format, any length of
>>> integer can be supported on any host.
>>>
>>> A new rtx type is created, the CONST_WIDE_INT, which contains a
>>> garbage collected array of HOST_WIDE_INTS that is large enough to hold
>>> the constant.  For the targets that define TARGET_SUPPORTS_WIDE_INT to
>>> be non zero, CONST_DOUBLES are only used to hold floating point
>>> values.  If the target leaves TARGET_SUPPORTS_WIDE_INT defined as 0,
>>> CONST_WIDE_INTs are not used and CONST_DOUBLEs are as they were
>>> before.
>>>
>>> CONST_INT does not change except that it is defined to hold all
>>> constants that fit in exactly one HOST_WIDE_INT.  Note that is slightly
>>> different than the current trunk.  Before this patch, the TImode
>>> constant '5' could either be in a CONST_INT or CONST_DOUBLE depending
>>> on which code path was used to create it.  This patch changes this so
>>> that if the constant fits in a CONST_INT then it is represented in a
>>> CONST_INT no matter how it is created.
>>>
>>> For the array inside a CONST_WIDE_INT, and internally in wide-int, we
>>> use a compressed form for integers that need more than one
>>> HOST_WIDE_INT.  Higher elements of the array are not needed if they
>>> are just a sign extension of the elements below them.  This does not
>>> imply that constants are signed or are sign extended, this is only a
>>> compression technique.
>>>
>>> While it might seem to be more esthetically pleasing to have not
>>> introduced the CONST_WIDE_INT and to have changed the representation
>>> of the CONST_INT to accomodate larger numbers, this would have both
>>> used more space and would be a time consuming change for the port
>>> maintainers.  We believe that most ports can be quickly converted with
>>> the current scheme because there is just not a lot of code in the back
>>> ends that cares about large constants.  Furthermore, the CONST_INT is
>>> very space efficient and even in a program that was heavy in large
>>> values, most constants would still fit in a CONST_INT.
>>>
>>> All of the parts of the rtl level that deal with CONST_DOUBLE as an
>>> now conditionally work with CONST_WIDE_INTs depending on the value
>>> of TARGET_SUPPORTS_WIDE_INT.  We believe that this patch removes all
>>> of the ices and wrong code places at the portable rtl level. However,
>>> there are still places in the portable rtl code that refuse to
>>> transform the code unless it is a CONST_INT.  Since these do not cause
>>> failures, they can be handled later.  The patch is already very large.
>>>
>>> It should be noted that much of the constant overflow checking in the
>>> constant math dissappears with these patches.  The overflow checking
>>> code in the current compiler is really divided into two cases:
>>> overflow on the host and overflow on the target.  The overflow
>>> checking on the host was to make sure that the math did overflow when
>>> done on two HOST_WIDE_INTs.  All of this code goes away.  These
>>> patches allow the constant math to be done exactly the way it is done
>>> on the target.
>>>
>>> This patch also aids other cleanups that are being considered at the
>>> rtl level:
>>>
>>>    1) These patches remove most of the host dependencies on the
>>>    optimizations.  Currently a 32 bit GCC host will produce different
>>>    code for a specific target than a 64 bit host will.  This is because
>>>    many of the transformations only work on constants that can be a
>>>    represented with a single HWI or two HWIs.  If the target has larger
>>>    integers than the host, the compilation suffers.
>>>
>>>    2) Bernd's need to make GCC correctly support partial its is made
>>>    easier by the wide-int library.  This library carefully does all
>>>    arithmetic in the precision of the mode included in it.  While there
>>>    are still places at the rtl level that still do arithmetic inline,
>>>    we plan to convert those to use the library over time.   This patch
>>>    converts a substantial number of those places.
>>>
>>>    3) This patch is one step along the path to add modes to rtl integer
>>>    constants.  There is no longer any checking to see if a CONST_DOUBLE
>>>    has VOIDmode as its mode.  Furthermore, all constructors for various
>>>    wide ints do take a mode and require that it not be VOIDmode. There
>>>    is still a lot of work to do to make this conversion possible.
>>>
>>> Richard Sandiford has been over the rtl portions of this patch a few
>>> times.  He has not looked at the wide-int files in any detail.  This
>>> patch has been heavily tested on my private ports and also on x86-64.
>>>
>>>
>>> CONVERSION PROCESS
>>>
>>> Converting a port mostly requires looking for the places where
>>> CONST_DOUBLES are used with VOIDmode and replacing that code with code
>>> that accesses CONST_WIDE_INTs.  "grep -i const_double" at the port
>>> level gets you to 95% of the changes that need to be made.  There are
>>> a few places that require a deeper look.
>>>
>>>    1) There is no equivalent to hval and lval for CONST_WIDE_INTs.
>>>    This would be difficult to express in the md language since there
>>>    are a variable number of elements.
>>>
>>>    Most ports only check that hval is either 0 or -1 to see if the int
>>>    is small.  As mentioned above, this will no longer be necessary
>>>    since small constants are always CONST_INT.  Of course there are
>>>    still a few exceptions, the alpha's constraint used by the zap
>>>    instruction certainly requires careful examination by C code.
>>>    However, all the current code does is pass the hval and lval to C
>>>    code, so evolving the c code to look at the CONST_WIDE_INT is not
>>>    really a large change.
>>>
>>>    2) Because there is no standard template that ports use to
>>>    materialize constants, there is likely to be some futzing that is
>>>    unique to each port in this code.
>>>
>>>    3) The rtx costs may have to be adjusted to properly account for
>>>    larger constants that are represented as CONST_WIDE_INT.
>>>
>>> All and all it has not taken us long to convert ports that we are
>>> familiar with.
>>>
>>> OTHER COMMENTS
>>>
>>> I did find what i believe is one interesting bug in the double-int
>>> code.  I believe that the code that performs divide and mod with round
>>> to nearest is seriously wrong for unsigned integers.  I believe that
>>> it will get the wrong answer for any numbers that are large enough to
>>> look negative if they consider signed integers.  Asside from that,
>>> wide-int should perform in a very similar manner to double-int.
>>>
>>> I am sorry for the size of this patch.   However, there does not appear
>>> to change the underlying data structure to support wider integers
>>> without doing something like this.
>>
>> Some pieces can be easily split out, like the introduction and use
>> of CONST_SCALAR_INT_P.
>>
>> As my general comment I would like to see double-int and wide-int
>> unified from an interface perspective.  Which means that double-int
>> should be a specialization of wide-int which should be a template
>> (which also means its size is constant).  Thus,
>>
>> typedef wide_int<2> double_int;
>>
>> should be the way to expose the double_int type.
>>
>> The main question remains - why does wide_int have a mode?
>> That looks redundant, both with information stored in types
>> and the RTL constant, and with the len field (that would be
>> always GET_MODE_SIZE () / ...?).  Also when you associate
>> a mode it's weird you don't associate a signedness.
>>
>> Thus I'd ask you to rework this to be a template on 'len'
>> (number of HOST_WIDE_INT words), drop the mode member
>> and unify double-int and wide-int.  Co-incidentially incrementally
>> doing this by converting double-int to a typedef of a
>> wide_int<2> specialization (thus moving double-int implementation
>> stuff to be wide_int<2> specialized) would be prefered.
>>
>> Btw,
>>
>> +/* Constructs tree in type TYPE from with value given by CST.  Signedness
>> +   of CST is assumed to be the same as the signedness of TYPE.  */
>> +
>> +tree
>> +wide_int_to_tree (tree type, const wide_int &cst)
>> +{
>> +  wide_int v;
>> +  if (TYPE_UNSIGNED (type))
>> +    v = cst.zext (TYPE_PRECISION (type));
>> +  else
>> +    v = cst.sext (TYPE_PRECISION (type));
>> +
>> +  return build_int_cst_wide (type, v.elt (0), v.elt (1));
>> +}
>>
>> is surely broken.  A wide-int does not fit a double-int.  How are you
>> going to "fix" this?
>>
>> Thanks,
>> Richard.
>>
>>> kenny
>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-04 16:58     ` Richard Guenther
@ 2012-10-04 18:08       ` Kenneth Zadeck
  2012-10-04 19:27         ` Richard Sandiford
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-04 18:08 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Mike Stump, Richard Sandiford, gcc-patches

On 10/04/2012 12:58 PM, Richard Guenther wrote:
> On Thu, Oct 4, 2012 at 3:55 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> Let me talk about the mode here first.
>>
>> What this interface/patch provides is a facility where the constant math
>> that is done in optimizations is done exactly the way that it would be done
>> on the target machine.   What we have now is a compiler that only does this
>> if it convenient to do on the host.   I admit that i care about this more
>> than others right now, but if intel adds a couple of more instructions to
>> their vector units, other people will start to really care about this issue.
>> If you take an OImode value with the current compiler and left shift it by
>> 250 the middle end will say that the result is 0.   This is just wrong!!!
>>
>> What this means is that the bitsize and precision of the operations need to
>> be carried along when doing math. when wide-int  checks for overflow on the
>> multiply or add, it is not checking the if the value overflowed on two HWIs,
>> it is checking if the add overflowed in the mode of the types that are
>> represented on the target.   When we do shift, we are not doing a shift
>> within two HWIs, we are truncating the shift value (if this is appropriate)
>> according to the bitsize and shifting according the precision.
>>
>> I think that an argument could be made that storing the mode should be
>> changed to an explicit precision and bitsize.  (A possible other option
>> would be to store a tree type, but this would make the usage at the rtl
>> level very cumbersome since types are rare.) Aside from the work, you would
>> not get much push back.
>>
>> But the signess is a different argument.   At the rtl level, the signess is
>> a matter of context.   (you could argue that this is a mistake and i would
>> agree, but that is an even bigger change.)   But more to the point, at the
>> tree level, there are a surprising number of places where the operation
>> desired does not follow the sign of the types that were used to construct
>> the constants.   Furthermore, not carrying the sign is more consistent with
>> the double int code, which as you point out carries nothing.
> Well, on RTL the signedness is on the operation (you have sdiv and udiv, etc.).
yes, there is a complete enough set of operations that allow you to 
specify the signess where this matters.

> double-int tries to present a sign-less twos-complement entity of size
> 2 * HOST_BITS_PER_WIDE_INT.  I think that is sensible and for
> obvious reasons should not change.  Both tree and RTL rely on this.
> What we do not want is that up to TImode you get an internal representation
> done one way (twos-complement) and on OImode and larger you
> suddenly get subtly different behavior.  That's a recepie for desaster.

This is the main difference between double-int and wide-int.    Wide int 
does the math the way the machine does it or the way the front end would 
expect it to be done.    There is nothing about the host that is visible 
in the interfaces.

I reiterate, our world is already bigger than 128 bits and the intel 
world is likely to be soon.   Double int is stuck in a 64/128 bit world. 
these patches, which i admit are huge, are a way out of that box.


> I'd like to clean up the interface to double-int some more (now with the
> nice C++ stuff we have).  double-int should be pure twos-complement,
> there should be no operations on double-ints that behave differently
> when done signed or unsigned, instead we have signed and unsigned
> versions of the operations (similar to how signedness is handled on
> the RTL level).  With some trivial C++ fu you could have a
> double_sint and double_uint type that would get rid of the bool
> sign params we have to some functions (and then you could
> write double_sint >> n using operator notation).

The problem is that size does matter.    wide int is effectively 
infinite precision twos complement.    In practice, we can get by by 
just looking at the bitsize and precision of the types/modes involved 
and this makes the implementation faster than true infinite precision.

I went done the road trying to fix all of the places where the compiler 
either iced or got the wrong answer.   I showed this to Sandiford and he 
talked me out of it.  He was right, it was a rat hole.  It could have 
been a smaller patch but it was there were places where it was clearly 
going to take monumental work just to be able to back out and say that 
you had nothing.    The number of places in the compiler where you 
compare against the largest and smallest representation of an integer is 
not small and some of them are buried very deep down chains that were 
not designed to say "i cannot answer that question".

I believe that i have all of the functionality of double int in wide 
int, it is just the calls look different because there are not all of 
the interfaces that take two HWI's.    As mentioned before, all of the 
places where the overflow is computed for the purpose of asking if this 
is ok in two hwi's is gone.


> I'd like wide-int (whatever it's internal representation is) to behave
> exactly like double-ints with respect to precision and signedness
> handling.  Ideally all static functions we have that operate on
> double-ints would be 1:1 available for wide-ints, so I can change
> the type of entities in an algorithm from double-ints to wide-ints
> (or vice versa) and do not have to change the code at all.
As mentioned above, this is not that easy.    the calls look very 
similar, but there are huge places in the both the rtl level and the 
tree level that just go away because you are always guaranteed to be 
doing things the way the target wants.    Look closely at the patch for 
simplify-rtx.   Huge blocks of code are gone AND THE COMPILER IS DOING 
MORE STUFF!!!!!

I will admit that the wide-int api is larger than the double-int 
one.     This means that a lot of things turn out to be very easy to do 
with wide ints that are cumbersome in double-int, like you can just 
return a number with a single bit set, or make a shifted, complemented 
mask in one call.

> Thus as first step I'd like you to go over the double-int stuff,
> compare it to the wide-int stuff you introduce and point out
> differences (changing double-ints or wide-ints to whatever is
> the more general concept).
My goal here is to get rid of double-int and have wide-int be the 
replacement.   The only real substantive difference between the two 
(aside from the divmod rounding issue i mentioned at the end of my first 
email) is that the clients no longer have to worry about overflow with 
respect to the host representation.  When overflow is returned, you know 
it is because the math overflowed in the type or mode of the integer 
operands.


> Now, as for 'modes' - similar to signedness some functions
> that operate on double-ints take a precision argument (like
> the various extensions).  You can add a similar wrapper
> type like double_sint, but this time with a cost - a new precision
> member, that can be constructed from a double_int (or wide_int)
> that ends up specifying the desired precision (be it in terms
> of a mode or a type).
>
> You didn't question my suggestion to have the number of
> HOST_WIDE_INTs in a wide-int be compile-time constant - was
> that just an oversight on your side?  The consequence is that
> code wanting to deal with arbitrary length wide-ints needs to
> be a template.
It was an oversight.   The number of HWIs is a compile time constant, it 
is just a compile time constant that is determined for you by looking at 
the target.   I went the extra mile to have this be automatically 
computed based on the target rather than putting in yet another target 
hook.

There is the issue about vrp needing something two times the size of the 
largest mode.    one way to solve that is just to get rid of mode inside 
the wide-int and keep an explicit precision and bitsize.  Then we could 
change the wide-int type to just use a 2x buffer.      Doing this would 
not be that expensive, except for vrp (which needed it anyway).   In 
almost all of the rest of the compiler, wide-ints are very short lived 
objects that just live on the stack.    So their size does not really 
effect anything.


>> As for the splitting out the patch in smaller pieces, i am all for it.   I
>> have done this twice already and i could get the const_scalar_int_p patch
>> out quickly.    But you do not get too far along that before you are still
>> left with a big patch.   I could split out wide-int.* and just commit those
>> files with no clients as a first step.   My guess is that Richard Sandiford
>> would appreciate that because while he has carefully checked the rtl stuff,
>> i think that the code inside wide-int is not in his comfort zone of things
>> he would approve.
>>
>> As far as your btw - noticed this last night.   it is an artifact of the way
>> i produced the patch and "responsible people have been sacked".   However,
>> it shows that you read the patch carefully, and i really appreciate that.
>> i owe you a beer (not that you need another at this time of year).
> You also didn't mention the missing tree bits ... was this just a 1/n patch
> or is it at all usable for you in this state?  Where do the large integers
> magically come from?
>
> Richard.

Yes, the tree bits are missing!!!  i am still working on them.   The 
plan was to have 2 patches, one for the rtl and one for the tree. the 
idea was that the rtl one could go in first.   Of course, if we can find 
ways to break this into more pieces, i agree that that helps.    i am a 
few days away from getting the tree patch out the door, and unlike the 
rtl patch, richard sandiford is not going to give the private comments.

My plan is to submit the tree patch as soon as possible, but before 
stage 1 closes (unless i could get an extension from a friendly release 
manager).


>> Kenny
>>
>>
>>
>> On 10/04/2012 08:48 AM, Richard Guenther wrote:
>>> On Wed, Oct 3, 2012 at 7:15 PM, Kenneth Zadeck <zadeck@naturalbridge.com>
>>> wrote:
>>>> The enclosed patch is the third of at least four patches that fix the
>>>> problems associated with supporting integers on the target that are
>>>> wider than two HOST_WIDE_INTs.
>>>>
>>>> While GCC claims to support OI mode, and we have two public ports that
>>>> make minor use of this mode, in practice, compilation that uses OImode
>>>> mode commonly gives the wrong result or ices.  We have a private port
>>>> of GCC for an architecture that is further down the road to needing
>>>> comprehensive OImode and we have discovered that this is unusable. We
>>>> have decided to fix it in a general way that so that it is most
>>>> beneficial to the GCC community.  It is our belief that we are just a
>>>> little ahead of the X86 and the NEON and these patches will shortly be
>>>> essential.
>>>>
>>>> The first two of these patches were primarily lexigraphical and have
>>>> already been committed.    They transformed the uses of CONST_DOUBLE
>>>> so that it is easy to tell what the intended usage is.
>>>>
>>>> The underlying structures in the next two patches are very general:
>>>> once they are added to the compiler, the compiler will be able to
>>>> support targets with any size of integer from hosts of any size
>>>> integer.
>>>>
>>>> The patch enclosed deals with the portable RTL parts of the compiler.
>>>> The next patch, which is currently under construction deals with the
>>>> tree level.  However, this patch can be put on the trunk as is, and it
>>>> will eleviate many, but not all of the current limitations in the rtl
>>>> parts of the compiler.
>>>>
>>>> Some of the patch is conditional, depending on a port defining the
>>>> symbol 'TARGET_SUPPORTS_WIDE_INT' to be non zero.  Defining this
>>>> symbol to be non zero is declaring that the port has been converted to
>>>> use the new form or integer constants.  However, the patch is
>>>> completely backwards compatible to allow ports that do not need this
>>>> immediately to convert at their leasure.  The conversion process is
>>>> not difficult, but it does require some knowledge of the port, so we
>>>> are not volinteering to do this for all ports.
>>>>
>>>> OVERVIEW OF THE PATCH:
>>>>
>>>> The patch defines a new datatype, a 'wide_int' (defined in
>>>> wide-int.[ch], and this datatype will be used to perform all of the
>>>> integer constant math in the compiler.  Externally, wide-int is very
>>>> similar to double-int except that it does not have the limitation that
>>>> math must be done on exactly two HOST_WIDE_INTs.
>>>>
>>>> Internally, a wide_int is a structure that contains a fixed sized
>>>> array of HOST_WIDE_INTs, a length field and a mode.  The size of the
>>> That it has a mode sounds odd to me and makes it subtly different
>>> from HOST_WIDE_INT and double-int.  Maybe the patch will tell
>>> why this is so.
>>>
>>>> array is determined at generation time by dividing the number of bits
>>>> of the largest integer supported on the target by the number of bits
>>>> in a HOST_WIDE_INT of the host.  Thus, with this format, any length of
>>>> integer can be supported on any host.
>>>>
>>>> A new rtx type is created, the CONST_WIDE_INT, which contains a
>>>> garbage collected array of HOST_WIDE_INTS that is large enough to hold
>>>> the constant.  For the targets that define TARGET_SUPPORTS_WIDE_INT to
>>>> be non zero, CONST_DOUBLES are only used to hold floating point
>>>> values.  If the target leaves TARGET_SUPPORTS_WIDE_INT defined as 0,
>>>> CONST_WIDE_INTs are not used and CONST_DOUBLEs are as they were
>>>> before.
>>>>
>>>> CONST_INT does not change except that it is defined to hold all
>>>> constants that fit in exactly one HOST_WIDE_INT.  Note that is slightly
>>>> different than the current trunk.  Before this patch, the TImode
>>>> constant '5' could either be in a CONST_INT or CONST_DOUBLE depending
>>>> on which code path was used to create it.  This patch changes this so
>>>> that if the constant fits in a CONST_INT then it is represented in a
>>>> CONST_INT no matter how it is created.
>>>>
>>>> For the array inside a CONST_WIDE_INT, and internally in wide-int, we
>>>> use a compressed form for integers that need more than one
>>>> HOST_WIDE_INT.  Higher elements of the array are not needed if they
>>>> are just a sign extension of the elements below them.  This does not
>>>> imply that constants are signed or are sign extended, this is only a
>>>> compression technique.
>>>>
>>>> While it might seem to be more esthetically pleasing to have not
>>>> introduced the CONST_WIDE_INT and to have changed the representation
>>>> of the CONST_INT to accomodate larger numbers, this would have both
>>>> used more space and would be a time consuming change for the port
>>>> maintainers.  We believe that most ports can be quickly converted with
>>>> the current scheme because there is just not a lot of code in the back
>>>> ends that cares about large constants.  Furthermore, the CONST_INT is
>>>> very space efficient and even in a program that was heavy in large
>>>> values, most constants would still fit in a CONST_INT.
>>>>
>>>> All of the parts of the rtl level that deal with CONST_DOUBLE as an
>>>> now conditionally work with CONST_WIDE_INTs depending on the value
>>>> of TARGET_SUPPORTS_WIDE_INT.  We believe that this patch removes all
>>>> of the ices and wrong code places at the portable rtl level. However,
>>>> there are still places in the portable rtl code that refuse to
>>>> transform the code unless it is a CONST_INT.  Since these do not cause
>>>> failures, they can be handled later.  The patch is already very large.
>>>>
>>>> It should be noted that much of the constant overflow checking in the
>>>> constant math dissappears with these patches.  The overflow checking
>>>> code in the current compiler is really divided into two cases:
>>>> overflow on the host and overflow on the target.  The overflow
>>>> checking on the host was to make sure that the math did overflow when
>>>> done on two HOST_WIDE_INTs.  All of this code goes away.  These
>>>> patches allow the constant math to be done exactly the way it is done
>>>> on the target.
>>>>
>>>> This patch also aids other cleanups that are being considered at the
>>>> rtl level:
>>>>
>>>>     1) These patches remove most of the host dependencies on the
>>>>     optimizations.  Currently a 32 bit GCC host will produce different
>>>>     code for a specific target than a 64 bit host will.  This is because
>>>>     many of the transformations only work on constants that can be a
>>>>     represented with a single HWI or two HWIs.  If the target has larger
>>>>     integers than the host, the compilation suffers.
>>>>
>>>>     2) Bernd's need to make GCC correctly support partial its is made
>>>>     easier by the wide-int library.  This library carefully does all
>>>>     arithmetic in the precision of the mode included in it.  While there
>>>>     are still places at the rtl level that still do arithmetic inline,
>>>>     we plan to convert those to use the library over time.   This patch
>>>>     converts a substantial number of those places.
>>>>
>>>>     3) This patch is one step along the path to add modes to rtl integer
>>>>     constants.  There is no longer any checking to see if a CONST_DOUBLE
>>>>     has VOIDmode as its mode.  Furthermore, all constructors for various
>>>>     wide ints do take a mode and require that it not be VOIDmode. There
>>>>     is still a lot of work to do to make this conversion possible.
>>>>
>>>> Richard Sandiford has been over the rtl portions of this patch a few
>>>> times.  He has not looked at the wide-int files in any detail.  This
>>>> patch has been heavily tested on my private ports and also on x86-64.
>>>>
>>>>
>>>> CONVERSION PROCESS
>>>>
>>>> Converting a port mostly requires looking for the places where
>>>> CONST_DOUBLES are used with VOIDmode and replacing that code with code
>>>> that accesses CONST_WIDE_INTs.  "grep -i const_double" at the port
>>>> level gets you to 95% of the changes that need to be made.  There are
>>>> a few places that require a deeper look.
>>>>
>>>>     1) There is no equivalent to hval and lval for CONST_WIDE_INTs.
>>>>     This would be difficult to express in the md language since there
>>>>     are a variable number of elements.
>>>>
>>>>     Most ports only check that hval is either 0 or -1 to see if the int
>>>>     is small.  As mentioned above, this will no longer be necessary
>>>>     since small constants are always CONST_INT.  Of course there are
>>>>     still a few exceptions, the alpha's constraint used by the zap
>>>>     instruction certainly requires careful examination by C code.
>>>>     However, all the current code does is pass the hval and lval to C
>>>>     code, so evolving the c code to look at the CONST_WIDE_INT is not
>>>>     really a large change.
>>>>
>>>>     2) Because there is no standard template that ports use to
>>>>     materialize constants, there is likely to be some futzing that is
>>>>     unique to each port in this code.
>>>>
>>>>     3) The rtx costs may have to be adjusted to properly account for
>>>>     larger constants that are represented as CONST_WIDE_INT.
>>>>
>>>> All and all it has not taken us long to convert ports that we are
>>>> familiar with.
>>>>
>>>> OTHER COMMENTS
>>>>
>>>> I did find what i believe is one interesting bug in the double-int
>>>> code.  I believe that the code that performs divide and mod with round
>>>> to nearest is seriously wrong for unsigned integers.  I believe that
>>>> it will get the wrong answer for any numbers that are large enough to
>>>> look negative if they consider signed integers.  Asside from that,
>>>> wide-int should perform in a very similar manner to double-int.
>>>>
>>>> I am sorry for the size of this patch.   However, there does not appear
>>>> to change the underlying data structure to support wider integers
>>>> without doing something like this.
>>> Some pieces can be easily split out, like the introduction and use
>>> of CONST_SCALAR_INT_P.
>>>
>>> As my general comment I would like to see double-int and wide-int
>>> unified from an interface perspective.  Which means that double-int
>>> should be a specialization of wide-int which should be a template
>>> (which also means its size is constant).  Thus,
>>>
>>> typedef wide_int<2> double_int;
>>>
>>> should be the way to expose the double_int type.
>>>
>>> The main question remains - why does wide_int have a mode?
>>> That looks redundant, both with information stored in types
>>> and the RTL constant, and with the len field (that would be
>>> always GET_MODE_SIZE () / ...?).  Also when you associate
>>> a mode it's weird you don't associate a signedness.
>>>
>>> Thus I'd ask you to rework this to be a template on 'len'
>>> (number of HOST_WIDE_INT words), drop the mode member
>>> and unify double-int and wide-int.  Co-incidentially incrementally
>>> doing this by converting double-int to a typedef of a
>>> wide_int<2> specialization (thus moving double-int implementation
>>> stuff to be wide_int<2> specialized) would be prefered.
>>>
>>> Btw,
>>>
>>> +/* Constructs tree in type TYPE from with value given by CST.  Signedness
>>> +   of CST is assumed to be the same as the signedness of TYPE.  */
>>> +
>>> +tree
>>> +wide_int_to_tree (tree type, const wide_int &cst)
>>> +{
>>> +  wide_int v;
>>> +  if (TYPE_UNSIGNED (type))
>>> +    v = cst.zext (TYPE_PRECISION (type));
>>> +  else
>>> +    v = cst.sext (TYPE_PRECISION (type));
>>> +
>>> +  return build_int_cst_wide (type, v.elt (0), v.elt (1));
>>> +}
>>>
>>> is surely broken.  A wide-int does not fit a double-int.  How are you
>>> going to "fix" this?
>>>
>>> Thanks,
>>> Richard.
>>>
>>>> kenny
>>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-04 18:08       ` Kenneth Zadeck
@ 2012-10-04 19:27         ` Richard Sandiford
  2012-10-05  9:27           ` Richard Guenther
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2012-10-04 19:27 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Richard Guenther, Mike Stump, gcc-patches

Kenneth Zadeck <zadeck@naturalbridge.com> writes:
> On 10/04/2012 12:58 PM, Richard Guenther wrote:
>> On Thu, Oct 4, 2012 at 3:55 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>>> Let me talk about the mode here first.
>>>
>>> What this interface/patch provides is a facility where the constant math
>>> that is done in optimizations is done exactly the way that it would be done
>>> on the target machine.   What we have now is a compiler that only does this
>>> if it convenient to do on the host.   I admit that i care about this more
>>> than others right now, but if intel adds a couple of more instructions to
>>> their vector units, other people will start to really care about this issue.
>>> If you take an OImode value with the current compiler and left shift it by
>>> 250 the middle end will say that the result is 0.   This is just wrong!!!
>>>
>>> What this means is that the bitsize and precision of the operations need to
>>> be carried along when doing math. when wide-int  checks for overflow on the
>>> multiply or add, it is not checking the if the value overflowed on two HWIs,
>>> it is checking if the add overflowed in the mode of the types that are
>>> represented on the target.   When we do shift, we are not doing a shift
>>> within two HWIs, we are truncating the shift value (if this is appropriate)
>>> according to the bitsize and shifting according the precision.
>>>
>>> I think that an argument could be made that storing the mode should be
>>> changed to an explicit precision and bitsize.  (A possible other option
>>> would be to store a tree type, but this would make the usage at the rtl
>>> level very cumbersome since types are rare.) Aside from the work, you would
>>> not get much push back.
>>>
>>> But the signess is a different argument.   At the rtl level, the signess is
>>> a matter of context.   (you could argue that this is a mistake and i would
>>> agree, but that is an even bigger change.)   But more to the point, at the
>>> tree level, there are a surprising number of places where the operation
>>> desired does not follow the sign of the types that were used to construct
>>> the constants.   Furthermore, not carrying the sign is more consistent with
>>> the double int code, which as you point out carries nothing.
>> Well, on RTL the signedness is on the operation (you have sdiv and udiv, etc.).
> yes, there is a complete enough set of operations that allow you to 
> specify the signess where this matters.
>
>> double-int tries to present a sign-less twos-complement entity of size
>> 2 * HOST_BITS_PER_WIDE_INT.  I think that is sensible and for
>> obvious reasons should not change.  Both tree and RTL rely on this.

I disagree, at least from an RTL perspective.  HOST_BITS_PER_WIDE_INT is
a host property, and as Kenny says, it's not really sensible to tie our
main target-specific IR to something host-specific.  We've only done
that for historical reasons.

On a target that's been converted to wide_int, I don't think a pair
of HWIs (whether or not it's expressed as a double_int) has any
significance at all at the RTL level.

As far as the wide_ints recording a mode or precision goes: we're in
the "lucky" position of having tried both options.  Trees record the
type (and thus precision) of all compile-time integer constants.
RTL doesn't.  And the RTL way is a right pain.  It leads to interfaces
in which rtx arguments often have to be accompanied by a mode.  And it
leads to clunky differences like those between simplify_unary_operation
(which takes two mode arguments) and simplify_binary_operation
(which with our current set of binary operations requires only one).

To put it another way: every wide_int operation needs to know
the precision of its arguments and the precision of its result.
Not storing the precision in the wide_int is putting the onus
on the caller to keep track of the precision separately.
And that just leads to the possibility of mismatches (e.g. from
accidentally passing the precision of a different wide_int instead;
the corresponding rtx mistake is easily made when you have several
variables with "mode" in their name).

Storing the precision in the wide_int means that we can assert for
such mismatches.  And those kinds of assert are much easier to debug,
because they trigger regardless of the integer values involved.
In contrast, RTL-level mismatches between CONST_INTs/CONST_DOUBLEs
and their accompanying mode have tended to trigger ICEs or wrong-code
bugs only for certain relatively uncommon inputs.  I.e. they're much
more likely to be found in the field rather than before release.

But let's say for the sake of argument that we went that way and didn't
record the precision in the wide_int.  We're unlikely to want interfaces
like:

    div (precision_of_result, precision_of_op0, op0,
         precsion_of_op1, op1)

because the three precisions are always going to be the same.
We'd have:

    div (precision_of_result, op0, op1)

instead.  So in cases where we "know" we're only going to be calling
wide_int interfaces like these, the callers will probably be lazy and
not keep track of op0 and op1's precision separately.  But the functions
like sign and zero extension, popcount, etc., will definitely need to
know the precision of their operand, and once we start using functions
like those, we will have to make the caller aware of the precision of
existing wide_ints.  It's not always easy to retrofit precision-tracking
code to the caller, and combine.c's handling of ZERO_EXTEND is one
example where we ended up deciding it was easier not to bother and just
avoid optimising ZERO_EXTENDs of constants instead.  See also cselib,
where we have to wrap certain types of rtl in a special CONST wrapper
(with added mode) so that we don't lose track.

And I think all that "need to know the precision" stuff applies to
double_int, except that the precision of a double_int is always
implicitly 2 * HOST_BITS_PER_WIDE_INT.  We don't want to hardcode
a similar precision for wide_int because it's always the precision
of the current operation, not the precision of the target's widest mode
(or whatever) that matters.

We only get away with using double_int (or more generally a pair of HWIs)
for RTL because (a) single HWI arithmetic tends to use a different path
and (b) no-one is making active use of modes with precisions in the range
(HOST_BITS_PER_WIDE_INT, 2 * HOST_BITS_PER_WIDE_INT).  If they were,
a lot of our current RTL code would be wrong, because we often don't
truncate intermediate or final 2-HWI values to the precision of the
result mode.

One of the advantages of wide_int is that it removes this (IMO) artifical
restriction "for free" (or in fact with less RTL code than we have now).
And that's not just academic: I think Kenny said that his target had
modes that are wider than 64 bits but not a power of 2 in width.

Sorry for the rant.  I just don't see any advantage to keeping the
precision and integer separate.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix
  2012-10-03 22:05   ` Kenneth Zadeck
  2012-10-04 13:17     ` Marc Glisse
@ 2012-10-04 21:06     ` Marc Glisse
  2012-10-04 23:02       ` Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Marc Glisse @ 2012-10-04 21:06 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: gcc-patches

On Wed, 3 Oct 2012, Kenneth Zadeck wrote:

> i have already converted the vrp code, so i have some guess at where you are 
> talking about.  (of course correct me if i am wrong).
>
> in the code that computes the range when two variables are multiplied 
> together needs to do a multiplication that produces a result that is twice as 
> wide as the inputs.
>
> my library is able to do that with one catch (and this is a big catch): the 
> target has to have an integer mode that is twice as big as the mode of the 
> operands. The issue is that wide-ints actually carry around the mode of the 
> value in order to get the bitsize and precision of the operands (it does not 
> have the type, because this code has to both work on the rtl and tree level 
> and i generally do not want the signness anyway).

Ah, after reading the whole thread, now I understand that it is because 
wide_int carries a mode that it makes little sense making it a template 
(sorry that it took me so long when the information was in your first 
answer). I understand that it would be inconvenient (much longer code) to 
have a base_wide_int that does just the arithmetic and a wrapper that 
contains the mode as well.

Your idea below to define dummy extra modes does bring the template idea 
back to the table though ;-)

> my current code in vrp checks to see if such a mode exists and if it does, it 
> produces the product.   if the mode does not exist, it returns bottom.   What 
> this means is that for most (many or some) targets that have a TImode, the 
> largest thing that particular vrp discover ranges for is a DImode value.   We 
> could get around this by defining the next larger mode than what the target 
> really needs but i wonder how much mileage you are going to get out of that 
> with really large numbers.

The current wrapping multiplication code in vrp works with a pair of 
double_int, so it should keep working with a pair of wide_int. I see now 
why wide_int doesn't allow to simplify the code, but it doesn't have to 
break.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix
  2012-10-04 21:06     ` Marc Glisse
@ 2012-10-04 23:02       ` Kenneth Zadeck
  2012-10-05  7:05         ` Marc Glisse
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-04 23:02 UTC (permalink / raw)
  To: Marc Glisse; +Cc: gcc-patches

There are a bunch of ways to skin the cat.

1) we can define the extra mode.
2) if we get rid of the mode inside the wide int and replace it with an 
explicit precision and bitsize, then we can just make the size of the 
buffer twice as big as the analysis of the modes indicates.
3) or we can leave your code in a form that uses 2 wide ints.   my 
current patch (which i have not gotten working yet) changes this to use 
the mul_full call, but it could be changed.   It is much simpler that 
the existing code.

i do not see how templates offer any solution at all.   the wide int 
code really needs to have something valid to indicate the length of the 
object, and if there is no mode that big, the code will ice.

my personal feeling is that range analysis is quite useful for small 
integers and not so much as the values get larger.   The only really 
large integer constants that you are likely to find in real code are 
encryption keys, like the dvd decoding keys, and if the key is chosen 
well there should be no useful optimization that you can perform on the 
code.   If this did not work on the largest modes, no one would ever 
notice.   i.e. i would bet that you never make a useful transformation 
on any integer that would not fit in an int32.

However, this is your pass, and i understand the principal of "never 
back down".

Kenny

On 10/04/2012 05:06 PM, Marc Glisse wrote:
> On Wed, 3 Oct 2012, Kenneth Zadeck wrote:
>
>> i have already converted the vrp code, so i have some guess at where 
>> you are talking about.  (of course correct me if i am wrong).
>>
>> in the code that computes the range when two variables are multiplied 
>> together needs to do a multiplication that produces a result that is 
>> twice as wide as the inputs.
>>
>> my library is able to do that with one catch (and this is a big 
>> catch): the target has to have an integer mode that is twice as big 
>> as the mode of the operands. The issue is that wide-ints actually 
>> carry around the mode of the value in order to get the bitsize and 
>> precision of the operands (it does not have the type, because this 
>> code has to both work on the rtl and tree level and i generally do 
>> not want the signness anyway).
>
> Ah, after reading the whole thread, now I understand that it is 
> because wide_int carries a mode that it makes little sense making it a 
> template (sorry that it took me so long when the information was in 
> your first answer). I understand that it would be inconvenient (much 
> longer code) to have a base_wide_int that does just the arithmetic and 
> a wrapper that contains the mode as well.
>
> Your idea below to define dummy extra modes does bring the template 
> idea back to the table though ;-)
>
>> my current code in vrp checks to see if such a mode exists and if it 
>> does, it produces the product.   if the mode does not exist, it 
>> returns bottom.   What this means is that for most (many or some) 
>> targets that have a TImode, the largest thing that particular vrp 
>> discover ranges for is a DImode value.   We could get around this by 
>> defining the next larger mode than what the target really needs but i 
>> wonder how much mileage you are going to get out of that with really 
>> large numbers.
>
> The current wrapping multiplication code in vrp works with a pair of 
> double_int, so it should keep working with a pair of wide_int. I see 
> now why wide_int doesn't allow to simplify the code, but it doesn't 
> have to break.
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix
  2012-10-04 23:02       ` Kenneth Zadeck
@ 2012-10-05  7:05         ` Marc Glisse
  0 siblings, 0 replies; 217+ messages in thread
From: Marc Glisse @ 2012-10-05  7:05 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: gcc-patches

On Thu, 4 Oct 2012, Kenneth Zadeck wrote:

> There are a bunch of ways to skin the cat.
>
> 1) we can define the extra mode.
> 2) if we get rid of the mode inside the wide int and replace it with an 
> explicit precision and bitsize, then we can just make the size of the buffer 
> twice as big as the analysis of the modes indicates.
> 3) or we can leave your code in a form that uses 2 wide ints.   my current 
> patch (which i have not gotten working yet) changes this to use the mul_full 
> call, but it could be changed.   It is much simpler that the existing code.

Thanks, we are exactly on the same page :-)

> i do not see how templates offer any solution at all.   the wide int code 
> really needs to have something valid to indicate the length of the object, 
> and if there is no mode that big, the code will ice.

It would be possible to define the regular wide_int taking into account 
only valid modes, and only use the dummy larger modes in very specific 
circumstances, where the template parameter would somehow indicate the 
last mode that may appear in it. This is not a recommendation at all, just 
an explanation of why templates might have had something to do with it.

> my personal feeling is that range analysis is quite useful for small integers 
> and not so much as the values get larger.   The only really large integer 
> constants that you are likely to find in real code are encryption keys,

Note that gcc regularly decides to use unsigned types where the code is 
signed, so a "small" constant like -1 can be huge.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-04 19:27         ` Richard Sandiford
@ 2012-10-05  9:27           ` Richard Guenther
  2012-10-05  9:29             ` Richard Guenther
  2012-10-05  9:56             ` Richard Sandiford
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Guenther @ 2012-10-05  9:27 UTC (permalink / raw)
  To: Kenneth Zadeck, Richard Guenther, Mike Stump, gcc-patches, rdsandiford

On Thu, Oct 4, 2012 at 9:27 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Kenneth Zadeck <zadeck@naturalbridge.com> writes:
>> On 10/04/2012 12:58 PM, Richard Guenther wrote:
>>> On Thu, Oct 4, 2012 at 3:55 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>>>> Let me talk about the mode here first.
>>>>
>>>> What this interface/patch provides is a facility where the constant math
>>>> that is done in optimizations is done exactly the way that it would be done
>>>> on the target machine.   What we have now is a compiler that only does this
>>>> if it convenient to do on the host.   I admit that i care about this more
>>>> than others right now, but if intel adds a couple of more instructions to
>>>> their vector units, other people will start to really care about this issue.
>>>> If you take an OImode value with the current compiler and left shift it by
>>>> 250 the middle end will say that the result is 0.   This is just wrong!!!
>>>>
>>>> What this means is that the bitsize and precision of the operations need to
>>>> be carried along when doing math. when wide-int  checks for overflow on the
>>>> multiply or add, it is not checking the if the value overflowed on two HWIs,
>>>> it is checking if the add overflowed in the mode of the types that are
>>>> represented on the target.   When we do shift, we are not doing a shift
>>>> within two HWIs, we are truncating the shift value (if this is appropriate)
>>>> according to the bitsize and shifting according the precision.
>>>>
>>>> I think that an argument could be made that storing the mode should be
>>>> changed to an explicit precision and bitsize.  (A possible other option
>>>> would be to store a tree type, but this would make the usage at the rtl
>>>> level very cumbersome since types are rare.) Aside from the work, you would
>>>> not get much push back.
>>>>
>>>> But the signess is a different argument.   At the rtl level, the signess is
>>>> a matter of context.   (you could argue that this is a mistake and i would
>>>> agree, but that is an even bigger change.)   But more to the point, at the
>>>> tree level, there are a surprising number of places where the operation
>>>> desired does not follow the sign of the types that were used to construct
>>>> the constants.   Furthermore, not carrying the sign is more consistent with
>>>> the double int code, which as you point out carries nothing.
>>> Well, on RTL the signedness is on the operation (you have sdiv and udiv, etc.).
>> yes, there is a complete enough set of operations that allow you to
>> specify the signess where this matters.
>>
>>> double-int tries to present a sign-less twos-complement entity of size
>>> 2 * HOST_BITS_PER_WIDE_INT.  I think that is sensible and for
>>> obvious reasons should not change.  Both tree and RTL rely on this.
>
> I disagree, at least from an RTL perspective.  HOST_BITS_PER_WIDE_INT is
> a host property, and as Kenny says, it's not really sensible to tie our
> main target-specific IR to something host-specific.  We've only done
> that for historical reasons.

Oh, I agree - that HOST_WIDE_INT provides the limit for the largest
integer constants we can encode on a target is a bug!

> On a target that's been converted to wide_int, I don't think a pair
> of HWIs (whether or not it's expressed as a double_int) has any
> significance at all at the RTL level.
>
> As far as the wide_ints recording a mode or precision goes: we're in
> the "lucky" position of having tried both options.  Trees record the
> type (and thus precision) of all compile-time integer constants.
> RTL doesn't.  And the RTL way is a right pain.  It leads to interfaces
> in which rtx arguments often have to be accompanied by a mode.  And it
> leads to clunky differences like those between simplify_unary_operation
> (which takes two mode arguments) and simplify_binary_operation
> (which with our current set of binary operations requires only one).

But the issue here is not that double_int doesn't record a mode
or precision (or a sign).  The issue is that CONST_DOUBLE and CONST_INT
don't!  The _tree_ INTEGER_CST contains of a type and a double-int.
I see double-int (and the proposed wide-int) as a common building-block
used for kind of "arbitrary precision" (as far as the target needs) integer
constants on both tree and RTL.  And having a common worker implementation
requires it to operate on something different than tree types or RTL mode
plus signedness.

> To put it another way: every wide_int operation needs to know
> the precision of its arguments and the precision of its result.

That's not true.  Every tree or RTL operation does, not every
wide_int operation.  double_int's are just twos-complement numbers
of precision 2 * HOST_BITS_PER_WIDE_INT.  wide_int's should
be just twos-complement numbers of precision len *
WHATEVER_HOST_COMPONENT_TYPE_IS_SUITABLE_FOR_A_FAST_IMPLEMENTATION.
Operations on double_int and wide_int are bare-metal,
in nearly all of the times you should use routines that do
proper sign-/zero-extending to a possibly smaller precision.  When
using bare-metal you are supposed to do that yourself.

Which is why I was suggesting to add double_sint, double_uint,
double_sintp (with precision), etc., wrappers and operations.

> Not storing the precision in the wide_int is putting the onus
> on the caller to keep track of the precision separately.

But that's a matter of providing something high-level ontop of
the bare-metal double-int/wide-int (something shared between
RTL and trees).  Duplicating information in the bare-metal
doesn't make sense (and no, INTEGER_CSTs on the tree level
are _not_ short-lived, and how can a double-int make sense on
the tree level when you say it doesn't make sense on the RTL level?)

> And that just leads to the possibility of mismatches (e.g. from
> accidentally passing the precision of a different wide_int instead;
> the corresponding rtx mistake is easily made when you have several
> variables with "mode" in their name).

Well, the mistake was obviously that CONST_INT/DOUBLE_INT
do not have a mode.  You are passing those RTXen, you are not
passing double-ints!  Don't blame double-ints for something that is
not their fault.

To me it looks like you want to create a CONST_WIDE, not a wide-int
(as you are not touching the tree side at all).  I'm all for that if that
is progress for you.  But make sure to provide an underlying
object type that is suitable for sharing between RTL and trees
(thus do not put in redundant information like a precision).

In the other mail Kenny mentioned that wide-ints are all of the same
compile-time, target specific size.  That might be suitable for
CONST_WIDE (on RTL you still have CONST_INT for integers that
can be encoded smaller, and we only have one function live in RTL
at a time) - but for trees certainly INTEGER_CSTs can consume
a significant portion of GC memory, so it's not an option to enlarge
it from containing two HWIs to what is required for 2 * OImode.
But again there is enough redundant information in the INTEGER_CST
(it's type which contains its mode) that allows it to be of variable size.

> Storing the precision in the wide_int means that we can assert for
> such mismatches.  And those kinds of assert are much easier to debug,
> because they trigger regardless of the integer values involved.
> In contrast, RTL-level mismatches between CONST_INTs/CONST_DOUBLEs
> and their accompanying mode have tended to trigger ICEs or wrong-code
> bugs only for certain relatively uncommon inputs.  I.e. they're much
> more likely to be found in the field rather than before release.
>
> But let's say for the sake of argument that we went that way and didn't
> record the precision in the wide_int.  We're unlikely to want interfaces
> like:
>
>     div (precision_of_result, precision_of_op0, op0,
>          precsion_of_op1, op1)
>
> because the three precisions are always going to be the same.
> We'd have:
>
>     div (precision_of_result, op0, op1)
>
> instead.  So in cases where we "know" we're only going to be calling
> wide_int interfaces like these, the callers will probably be lazy and
> not keep track of op0 and op1's precision separately.  But the functions
> like sign and zero extension, popcount, etc., will definitely need to
> know the precision of their operand, and once we start using functions
> like those, we will have to make the caller aware of the precision of
> existing wide_ints.  It's not always easy to retrofit precision-tracking
> code to the caller, and combine.c's handling of ZERO_EXTEND is one
> example where we ended up deciding it was easier not to bother and just
> avoid optimising ZERO_EXTENDs of constants instead.  See also cselib,
> where we have to wrap certain types of rtl in a special CONST wrapper
> (with added mode) so that we don't lose track.
>
> And I think all that "need to know the precision" stuff applies to
> double_int, except that the precision of a double_int is always
> implicitly 2 * HOST_BITS_PER_WIDE_INT.  We don't want to hardcode
> a similar precision for wide_int because it's always the precision
> of the current operation, not the precision of the target's widest mode
> (or whatever) that matters.
>
> We only get away with using double_int (or more generally a pair of HWIs)
> for RTL because (a) single HWI arithmetic tends to use a different path
> and (b) no-one is making active use of modes with precisions in the range
> (HOST_BITS_PER_WIDE_INT, 2 * HOST_BITS_PER_WIDE_INT).  If they were,
> a lot of our current RTL code would be wrong, because we often don't
> truncate intermediate or final 2-HWI values to the precision of the
> result mode.
>
> One of the advantages of wide_int is that it removes this (IMO) artifical
> restriction "for free" (or in fact with less RTL code than we have now).
> And that's not just academic: I think Kenny said that his target had
> modes that are wider than 64 bits but not a power of 2 in width.
>
> Sorry for the rant.  I just don't see any advantage to keeping the
> precision and integer separate.

Avoiding redundant information (which can get out of sync) for something
that is supposed to be shared between tree and RTL (is it?!).

So, I think you want a CONST_WIDE RTX that has

struct const_wide_rtx {
  wide_int w;
  enum machine_mode mode;
};

which, if I look close enough, we already have (in struct rtx_def we _do_
have a mode field).

So I'm not really sure what your issue is?

Look at RTL users of the double-int routines and provide wrappers
that take RTXen as inputs.  Enforce that all CONSTs have a mode.

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05  9:27           ` Richard Guenther
@ 2012-10-05  9:29             ` Richard Guenther
  2012-10-05  9:56             ` Richard Sandiford
  1 sibling, 0 replies; 217+ messages in thread
From: Richard Guenther @ 2012-10-05  9:29 UTC (permalink / raw)
  To: Kenneth Zadeck, Richard Guenther, Mike Stump, gcc-patches, rdsandiford

On Fri, Oct 5, 2012 at 11:26 AM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> Look at RTL users of the double-int routines and provide wrappers
> that take RTXen as inputs.  Enforce that all CONSTs have a mode.

Which would, btw, allow to "merge" CONST_INT, CONST_DOUBLE
and CONST_WIDE by making the storage size variable and it's
length specified by the mode of the RTX (I never liked the distinction
of CONST_INT and CONST_DOUBLE, and you are right, the
CONST_DOUBLE paths are seldomly excercised).

Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05  9:27           ` Richard Guenther
  2012-10-05  9:29             ` Richard Guenther
@ 2012-10-05  9:56             ` Richard Sandiford
  2012-10-05 10:34               ` Richard Guenther
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2012-10-05  9:56 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Kenneth Zadeck, Mike Stump, gcc-patches

Richard Guenther <richard.guenther@gmail.com> writes:
>> As far as the wide_ints recording a mode or precision goes: we're in
>> the "lucky" position of having tried both options.  Trees record the
>> type (and thus precision) of all compile-time integer constants.
>> RTL doesn't.  And the RTL way is a right pain.  It leads to interfaces
>> in which rtx arguments often have to be accompanied by a mode.  And it
>> leads to clunky differences like those between simplify_unary_operation
>> (which takes two mode arguments) and simplify_binary_operation
>> (which with our current set of binary operations requires only one).
>
> But the issue here is not that double_int doesn't record a mode
> or precision (or a sign).  The issue is that CONST_DOUBLE and CONST_INT
> don't!  The _tree_ INTEGER_CST contains of a type and a double-int.
> I see double-int (and the proposed wide-int) as a common building-block
> used for kind of "arbitrary precision" (as far as the target needs) integer
> constants on both tree and RTL.  And having a common worker implementation
> requires it to operate on something different than tree types or RTL mode
> plus signedness.
>
>> To put it another way: every wide_int operation needs to know
>> the precision of its arguments and the precision of its result.
>
> That's not true.  Every tree or RTL operation does, not every
> wide_int operation.  double_int's are just twos-complement numbers
> of precision 2 * HOST_BITS_PER_WIDE_INT.  wide_int's should
> be just twos-complement numbers of precision len *
> WHATEVER_HOST_COMPONENT_TYPE_IS_SUITABLE_FOR_A_FAST_IMPLEMENTATION.
> Operations on double_int and wide_int are bare-metal,
> in nearly all of the times you should use routines that do
> proper sign-/zero-extending to a possibly smaller precision.  When
> using bare-metal you are supposed to do that yourself.
>
> Which is why I was suggesting to add double_sint, double_uint,
> double_sintp (with precision), etc., wrappers and operations.
>
>> Not storing the precision in the wide_int is putting the onus
>> on the caller to keep track of the precision separately.
>
> But that's a matter of providing something high-level ontop of
> the bare-metal double-int/wide-int (something shared between
> RTL and trees).  Duplicating information in the bare-metal
> doesn't make sense (and no, INTEGER_CSTs on the tree level
> are _not_ short-lived, and how can a double-int make sense on
> the tree level when you say it doesn't make sense on the RTL level?)

I think we're talking at cross purposes here.  To the extent that
I'm not really sure where to begin. :-)  Just in case this is it:
the idea is that wide_int is the type used to _process_ integers.
It is not suppoed to be the type used to store integers in the IRs.
The way trees store integers and the way that RTL stores integers
are up to them.  For RTL the idea is that we continue to store integers
that happen to fit into a HWI as a CONST_INT (regardless of the size of
the CONST_INT's context-determined mode).  Wider integers are stored
as a CONST_DOUBLE (for unconverted targets) or a CONST_WIDE_INT
(for converted targets).  None of the three use the wide_int type;
they use more compact representations instead.  And as Kenny says,
using CONST_INT continues to be an important way of reducing the
IR footprint.

Whenever we want to do something interesting with the integers,
we construct a wide_int for them and use the same processing code
for all three rtx types.  This avoids having the separate single-HWI
and double-HWI paths that we have now.  It also copes naturally with
cases where we start out with single-HWI values but end up with wider
ones.

But the operations that we do on these wide_ints will all be to a mode
or precision.  Shifts of QImode integers are different from shifts of
HImode integers, etc.

If you knew all that already (you probably did) and I've completely
missed the point, please say so. :-)

I'm not sure what you mean by "bare metal".

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05  9:56             ` Richard Sandiford
@ 2012-10-05 10:34               ` Richard Guenther
  2012-10-05 11:24                 ` Richard Sandiford
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Guenther @ 2012-10-05 10:34 UTC (permalink / raw)
  To: Richard Guenther, Kenneth Zadeck, Mike Stump, gcc-patches, rdsandiford

On Fri, Oct 5, 2012 at 11:55 AM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Guenther <richard.guenther@gmail.com> writes:
>>> As far as the wide_ints recording a mode or precision goes: we're in
>>> the "lucky" position of having tried both options.  Trees record the
>>> type (and thus precision) of all compile-time integer constants.
>>> RTL doesn't.  And the RTL way is a right pain.  It leads to interfaces
>>> in which rtx arguments often have to be accompanied by a mode.  And it
>>> leads to clunky differences like those between simplify_unary_operation
>>> (which takes two mode arguments) and simplify_binary_operation
>>> (which with our current set of binary operations requires only one).
>>
>> But the issue here is not that double_int doesn't record a mode
>> or precision (or a sign).  The issue is that CONST_DOUBLE and CONST_INT
>> don't!  The _tree_ INTEGER_CST contains of a type and a double-int.
>> I see double-int (and the proposed wide-int) as a common building-block
>> used for kind of "arbitrary precision" (as far as the target needs) integer
>> constants on both tree and RTL.  And having a common worker implementation
>> requires it to operate on something different than tree types or RTL mode
>> plus signedness.
>>
>>> To put it another way: every wide_int operation needs to know
>>> the precision of its arguments and the precision of its result.
>>
>> That's not true.  Every tree or RTL operation does, not every
>> wide_int operation.  double_int's are just twos-complement numbers
>> of precision 2 * HOST_BITS_PER_WIDE_INT.  wide_int's should
>> be just twos-complement numbers of precision len *
>> WHATEVER_HOST_COMPONENT_TYPE_IS_SUITABLE_FOR_A_FAST_IMPLEMENTATION.
>> Operations on double_int and wide_int are bare-metal,
>> in nearly all of the times you should use routines that do
>> proper sign-/zero-extending to a possibly smaller precision.  When
>> using bare-metal you are supposed to do that yourself.
>>
>> Which is why I was suggesting to add double_sint, double_uint,
>> double_sintp (with precision), etc., wrappers and operations.
>>
>>> Not storing the precision in the wide_int is putting the onus
>>> on the caller to keep track of the precision separately.
>>
>> But that's a matter of providing something high-level ontop of
>> the bare-metal double-int/wide-int (something shared between
>> RTL and trees).  Duplicating information in the bare-metal
>> doesn't make sense (and no, INTEGER_CSTs on the tree level
>> are _not_ short-lived, and how can a double-int make sense on
>> the tree level when you say it doesn't make sense on the RTL level?)
>
> I think we're talking at cross purposes here.  To the extent that
> I'm not really sure where to begin. :-)  Just in case this is it:
> the idea is that wide_int is the type used to _process_ integers.
> It is not suppoed to be the type used to store integers in the IRs.
> The way trees store integers and the way that RTL stores integers
> are up to them.  For RTL the idea is that we continue to store integers
> that happen to fit into a HWI as a CONST_INT (regardless of the size of
> the CONST_INT's context-determined mode).  Wider integers are stored
> as a CONST_DOUBLE (for unconverted targets) or a CONST_WIDE_INT
> (for converted targets).  None of the three use the wide_int type;
> they use more compact representations instead.  And as Kenny says,
> using CONST_INT continues to be an important way of reducing the
> IR footprint.
>
> Whenever we want to do something interesting with the integers,
> we construct a wide_int for them and use the same processing code
> for all three rtx types.  This avoids having the separate single-HWI
> and double-HWI paths that we have now.  It also copes naturally with
> cases where we start out with single-HWI values but end up with wider
> ones.
>
> But the operations that we do on these wide_ints will all be to a mode
> or precision.  Shifts of QImode integers are different from shifts of
> HImode integers, etc.
>
> If you knew all that already (you probably did) and I've completely
> missed the point, please say so. :-)
>
> I'm not sure what you mean by "bare metal".

The issue is that unlike RTL where we "construct" double-ints from
CONST_INT/CONST_DOUBLE right now, tree has the double-int
_embedded_.  That's why I say that the thing we embed in
a CONST_WIDE_INT or a tree INTEGER_CST needs to be
"bare metal", and that's what I would call wide-int.

I think you have two things mixed in this patch which might add to
the confusion (heh).  One is, making the thing you work on in RTL
(which used to be double-ints before this patch) be wide-ints
which carry additional information taken from the IL RTX piece
at construction time.  That's all nice and good.  The other thing
is adding a CONST_WIDE_INT to support wider integer constants
than the weird host-dependent limitation we have right now.
Mixing those things together probably made you be able to make
Kenny work on it ... heh ;)

So to me wide-ints provide the higher-level abstraction ontop of
double-ints (which would remain the storage entity).  Such
higher-level abstraction is very useful, also for double-ints and
also on the tree level.  There is no requirement to provide bigger
double-int (or wide-int) for this.  Let's call this abstraction
wide-int (as opposed to my suggested more piecemail double_sint,
double_uint).  You can perfectly model it ontop of the existing
double_int storage.

As of providing larger "double-ints" - there is not much code left
(ok, quite an overstatement ;)) that relies on the implementation
detail of double-int containing exactly two HOST_WIDE_INTs.
The exact purpose of double-ints was to _hide_ this (previously
we only had routines like mul_double_with_sign which take
two HOST_WIDE_INT components).  Most code dealing with
the implementation detail is code interfacing with middle-end
routines that take a HOST_WIDE_INT argument (thus the
double_int_fits_hwi_p predicates) - even wide_int has to support
this kind of interfacing.

So, after introducing wide_int that just wraps double_int and
changing all user code (hopefully all, I guess mostly all), we'd
tackle the issue that the size of double_int's is host dependent.
A simple solution is to make it's size dependent on a target macro
(yes, macro ...), so on a 32bit HWI host targeting a 64bit 'HWI' target
you'd simply have four HWIs in the 'double-int' storage (and
arithmetic needs to be generalized to support this).

[The more complex solution makes double-int* just a pointer to the first
HWI, so it cannot be used without being "wrapped" in a wide-int
which implicitely would provide the number of HWIs pointed to
(yes, I think variable-sized wide-int storage is the ultimate way to go).]

So ... can you possibly split the patch in a way that just does the
first thing (provide the high-level wrapper and make use of it from RTL)?
I don't see the reason to have both CONST_DOUBLE and CONST_WIDE,
in fact they should be the same given choice one for the 2nd step.
And you can of course trivially construct a wide-int from a CONST_INT
as well (given it has a mode).

As of using a mode or precision in wide-int - for re-use on the tree level
you need a precision as not all precisions have a distinct mode.  As on
RTL you don't have a sign we probably don't want wide-ints to have a sign
but continue double-int-like to specify the sign as part of the operation
where it matters.

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 10:34               ` Richard Guenther
@ 2012-10-05 11:24                 ` Richard Sandiford
  2012-10-05 11:42                   ` Richard Guenther
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2012-10-05 11:24 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Kenneth Zadeck, Mike Stump, gcc-patches

Richard Guenther <richard.guenther@gmail.com> writes:
> On Fri, Oct 5, 2012 at 11:55 AM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Guenther <richard.guenther@gmail.com> writes:
>>>> As far as the wide_ints recording a mode or precision goes: we're in
>>>> the "lucky" position of having tried both options.  Trees record the
>>>> type (and thus precision) of all compile-time integer constants.
>>>> RTL doesn't.  And the RTL way is a right pain.  It leads to interfaces
>>>> in which rtx arguments often have to be accompanied by a mode.  And it
>>>> leads to clunky differences like those between simplify_unary_operation
>>>> (which takes two mode arguments) and simplify_binary_operation
>>>> (which with our current set of binary operations requires only one).
>>>
>>> But the issue here is not that double_int doesn't record a mode
>>> or precision (or a sign).  The issue is that CONST_DOUBLE and CONST_INT
>>> don't!  The _tree_ INTEGER_CST contains of a type and a double-int.
>>> I see double-int (and the proposed wide-int) as a common building-block
>>> used for kind of "arbitrary precision" (as far as the target needs) integer
>>> constants on both tree and RTL.  And having a common worker implementation
>>> requires it to operate on something different than tree types or RTL mode
>>> plus signedness.
>>>
>>>> To put it another way: every wide_int operation needs to know
>>>> the precision of its arguments and the precision of its result.
>>>
>>> That's not true.  Every tree or RTL operation does, not every
>>> wide_int operation.  double_int's are just twos-complement numbers
>>> of precision 2 * HOST_BITS_PER_WIDE_INT.  wide_int's should
>>> be just twos-complement numbers of precision len *
>>> WHATEVER_HOST_COMPONENT_TYPE_IS_SUITABLE_FOR_A_FAST_IMPLEMENTATION.
>>> Operations on double_int and wide_int are bare-metal,
>>> in nearly all of the times you should use routines that do
>>> proper sign-/zero-extending to a possibly smaller precision.  When
>>> using bare-metal you are supposed to do that yourself.
>>>
>>> Which is why I was suggesting to add double_sint, double_uint,
>>> double_sintp (with precision), etc., wrappers and operations.
>>>
>>>> Not storing the precision in the wide_int is putting the onus
>>>> on the caller to keep track of the precision separately.
>>>
>>> But that's a matter of providing something high-level ontop of
>>> the bare-metal double-int/wide-int (something shared between
>>> RTL and trees).  Duplicating information in the bare-metal
>>> doesn't make sense (and no, INTEGER_CSTs on the tree level
>>> are _not_ short-lived, and how can a double-int make sense on
>>> the tree level when you say it doesn't make sense on the RTL level?)
>>
>> I think we're talking at cross purposes here.  To the extent that
>> I'm not really sure where to begin. :-)  Just in case this is it:
>> the idea is that wide_int is the type used to _process_ integers.
>> It is not suppoed to be the type used to store integers in the IRs.
>> The way trees store integers and the way that RTL stores integers
>> are up to them.  For RTL the idea is that we continue to store integers
>> that happen to fit into a HWI as a CONST_INT (regardless of the size of
>> the CONST_INT's context-determined mode).  Wider integers are stored
>> as a CONST_DOUBLE (for unconverted targets) or a CONST_WIDE_INT
>> (for converted targets).  None of the three use the wide_int type;
>> they use more compact representations instead.  And as Kenny says,
>> using CONST_INT continues to be an important way of reducing the
>> IR footprint.
>>
>> Whenever we want to do something interesting with the integers,
>> we construct a wide_int for them and use the same processing code
>> for all three rtx types.  This avoids having the separate single-HWI
>> and double-HWI paths that we have now.  It also copes naturally with
>> cases where we start out with single-HWI values but end up with wider
>> ones.
>>
>> But the operations that we do on these wide_ints will all be to a mode
>> or precision.  Shifts of QImode integers are different from shifts of
>> HImode integers, etc.
>>
>> If you knew all that already (you probably did) and I've completely
>> missed the point, please say so. :-)
>>
>> I'm not sure what you mean by "bare metal".
>
> The issue is that unlike RTL where we "construct" double-ints from
> CONST_INT/CONST_DOUBLE right now, tree has the double-int
> _embedded_.  That's why I say that the thing we embed in
> a CONST_WIDE_INT or a tree INTEGER_CST needs to be
> "bare metal", and that's what I would call wide-int.

OK, but that's deliberately not what Kenny's patch calls "wide int".
The whole idea is that the "bare metal" thing we embed in a
CONST_WIDE_INT or tree isn't (and doesn't need to be) the same
as the type that we use to operate on integers.  That bare-metal
thing doesn't even have to have a fixed width.  (CONST_WIDE_INT
doesn't have a fixed width, it's only as big as the integer
needs it to be.)

> So to me wide-ints provide the higher-level abstraction ontop of
> double-ints (which would remain the storage entity).
>
> Such higher-level abstraction is very useful, also for double-ints and
> also on the tree level.  There is no requirement to provide bigger
> double-int (or wide-int) for this.  Let's call this abstraction
> wide-int (as opposed to my suggested more piecemail double_sint,
> double_uint).  You can perfectly model it ontop of the existing
> double_int storage.
>
> As of providing larger "double-ints" - there is not much code left
> (ok, quite an overstatement ;)) that relies on the implementation
> detail of double-int containing exactly two HOST_WIDE_INTs.
> The exact purpose of double-ints was to _hide_ this (previously
> we only had routines like mul_double_with_sign which take
> two HOST_WIDE_INT components).  Most code dealing with
> the implementation detail is code interfacing with middle-end
> routines that take a HOST_WIDE_INT argument (thus the
> double_int_fits_hwi_p predicates) - even wide_int has to support
> this kind of interfacing.
>
> So, after introducing wide_int that just wraps double_int and
> changing all user code (hopefully all, I guess mostly all), we'd
> tackle the issue that the size of double_int's is host dependent.
> A simple solution is to make it's size dependent on a target macro
> (yes, macro ...), so on a 32bit HWI host targeting a 64bit 'HWI' target
> you'd simply have four HWIs in the 'double-int' storage (and
> arithmetic needs to be generalized to support this).

I just don't see why this is a good thing.  The constraints
are different when storing integers and when operating on them.
When operating on them, we want something that is easily constructed
on the stack, so we can create temporary structures very cheaply,
and can easily pass and return them.  We happen to know at GCC's
compile time how big the biggest integer will ever be, so it makes
sense for wide_int to be that wide.

But when storing integers we want something compact.  If your
machine supports 256-bit integers, but the code you're compiling
makes heavy use of 128-bit integers, why would you want to waste
128 of 256 bits on every stored integer?  Which is why even
CONST_WIDE_INT doesn't have a fixed width.

You seem to be arguing that the type used to store integers in the IR
has to be same as the one that we use when performing compile-time
arithmetic, but I think it's better to have an abstraction between
the two.

So if you think a pair of HWIs continues to be a useful way of
storing integers at the tree level, then we can easily continue
to use a pair of HWIs there.  Or if you'd prefer every tree integer
to be the same width as a wide_int, we can do that too.  (I don't
know what Kenny's tree patch does.)  But the whole point of having
wide_int as an abstraction is that most code _operating_ on integers
doesn't care what the representation is.  It becomes much easier to
change that representation to whatever gives the best performance.

Another advantage of abstracting away the storage type is that
we could store things like an overflow flag in the wide_int
(if that ever proves useful) without worrying about the impact
on the tree and RTL footprint.

> [The more complex solution makes double-int* just a pointer to the first
> HWI, so it cannot be used without being "wrapped" in a wide-int
> which implicitely would provide the number of HWIs pointed to
> (yes, I think variable-sized wide-int storage is the ultimate way to go).]
>
> So ... can you possibly split the patch in a way that just does the
> first thing (provide the high-level wrapper and make use of it from RTL)?
> I don't see the reason to have both CONST_DOUBLE and CONST_WIDE,
> in fact they should be the same given choice one for the 2nd step.
> And you can of course trivially construct a wide-int from a CONST_INT
> as well (given it has a mode).
>
> As of using a mode or precision in wide-int - for re-use on the tree level
> you need a precision as not all precisions have a distinct mode.  As on
> RTL you don't have a sign we probably don't want wide-ints to have a sign
> but continue double-int-like to specify the sign as part of the operation
> where it matters.

Definitely agree that signedness is a property of the operation.
(Saturation too IMO.)  I don't really mind about mode vs. precision.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 11:24                 ` Richard Sandiford
@ 2012-10-05 11:42                   ` Richard Guenther
  2012-10-05 12:26                     ` Richard Sandiford
  2012-10-05 13:11                     ` Kenneth Zadeck
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Guenther @ 2012-10-05 11:42 UTC (permalink / raw)
  To: Richard Guenther, Kenneth Zadeck, Mike Stump, gcc-patches, rdsandiford

On Fri, Oct 5, 2012 at 1:24 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Guenther <richard.guenther@gmail.com> writes:
>> On Fri, Oct 5, 2012 at 11:55 AM, Richard Sandiford
>> <rdsandiford@googlemail.com> wrote:
>>> Richard Guenther <richard.guenther@gmail.com> writes:
>>>>> As far as the wide_ints recording a mode or precision goes: we're in
>>>>> the "lucky" position of having tried both options.  Trees record the
>>>>> type (and thus precision) of all compile-time integer constants.
>>>>> RTL doesn't.  And the RTL way is a right pain.  It leads to interfaces
>>>>> in which rtx arguments often have to be accompanied by a mode.  And it
>>>>> leads to clunky differences like those between simplify_unary_operation
>>>>> (which takes two mode arguments) and simplify_binary_operation
>>>>> (which with our current set of binary operations requires only one).
>>>>
>>>> But the issue here is not that double_int doesn't record a mode
>>>> or precision (or a sign).  The issue is that CONST_DOUBLE and CONST_INT
>>>> don't!  The _tree_ INTEGER_CST contains of a type and a double-int.
>>>> I see double-int (and the proposed wide-int) as a common building-block
>>>> used for kind of "arbitrary precision" (as far as the target needs) integer
>>>> constants on both tree and RTL.  And having a common worker implementation
>>>> requires it to operate on something different than tree types or RTL mode
>>>> plus signedness.
>>>>
>>>>> To put it another way: every wide_int operation needs to know
>>>>> the precision of its arguments and the precision of its result.
>>>>
>>>> That's not true.  Every tree or RTL operation does, not every
>>>> wide_int operation.  double_int's are just twos-complement numbers
>>>> of precision 2 * HOST_BITS_PER_WIDE_INT.  wide_int's should
>>>> be just twos-complement numbers of precision len *
>>>> WHATEVER_HOST_COMPONENT_TYPE_IS_SUITABLE_FOR_A_FAST_IMPLEMENTATION.
>>>> Operations on double_int and wide_int are bare-metal,
>>>> in nearly all of the times you should use routines that do
>>>> proper sign-/zero-extending to a possibly smaller precision.  When
>>>> using bare-metal you are supposed to do that yourself.
>>>>
>>>> Which is why I was suggesting to add double_sint, double_uint,
>>>> double_sintp (with precision), etc., wrappers and operations.
>>>>
>>>>> Not storing the precision in the wide_int is putting the onus
>>>>> on the caller to keep track of the precision separately.
>>>>
>>>> But that's a matter of providing something high-level ontop of
>>>> the bare-metal double-int/wide-int (something shared between
>>>> RTL and trees).  Duplicating information in the bare-metal
>>>> doesn't make sense (and no, INTEGER_CSTs on the tree level
>>>> are _not_ short-lived, and how can a double-int make sense on
>>>> the tree level when you say it doesn't make sense on the RTL level?)
>>>
>>> I think we're talking at cross purposes here.  To the extent that
>>> I'm not really sure where to begin. :-)  Just in case this is it:
>>> the idea is that wide_int is the type used to _process_ integers.
>>> It is not suppoed to be the type used to store integers in the IRs.
>>> The way trees store integers and the way that RTL stores integers
>>> are up to them.  For RTL the idea is that we continue to store integers
>>> that happen to fit into a HWI as a CONST_INT (regardless of the size of
>>> the CONST_INT's context-determined mode).  Wider integers are stored
>>> as a CONST_DOUBLE (for unconverted targets) or a CONST_WIDE_INT
>>> (for converted targets).  None of the three use the wide_int type;
>>> they use more compact representations instead.  And as Kenny says,
>>> using CONST_INT continues to be an important way of reducing the
>>> IR footprint.
>>>
>>> Whenever we want to do something interesting with the integers,
>>> we construct a wide_int for them and use the same processing code
>>> for all three rtx types.  This avoids having the separate single-HWI
>>> and double-HWI paths that we have now.  It also copes naturally with
>>> cases where we start out with single-HWI values but end up with wider
>>> ones.
>>>
>>> But the operations that we do on these wide_ints will all be to a mode
>>> or precision.  Shifts of QImode integers are different from shifts of
>>> HImode integers, etc.
>>>
>>> If you knew all that already (you probably did) and I've completely
>>> missed the point, please say so. :-)
>>>
>>> I'm not sure what you mean by "bare metal".
>>
>> The issue is that unlike RTL where we "construct" double-ints from
>> CONST_INT/CONST_DOUBLE right now, tree has the double-int
>> _embedded_.  That's why I say that the thing we embed in
>> a CONST_WIDE_INT or a tree INTEGER_CST needs to be
>> "bare metal", and that's what I would call wide-int.
>
> OK, but that's deliberately not what Kenny's patch calls "wide int".
> The whole idea is that the "bare metal" thing we embed in a
> CONST_WIDE_INT or tree isn't (and doesn't need to be) the same
> as the type that we use to operate on integers.  That bare-metal
> thing doesn't even have to have a fixed width.  (CONST_WIDE_INT
> doesn't have a fixed width, it's only as big as the integer
> needs it to be.)

Ok, let's rephrase it this way then: the "bare metal" thing used
for the storage should ideally be the same in the tree IL and the RTL
IL _and_ the higher-level abstract wide-int.

>> So to me wide-ints provide the higher-level abstraction ontop of
>> double-ints (which would remain the storage entity).
>>
>> Such higher-level abstraction is very useful, also for double-ints and
>> also on the tree level.  There is no requirement to provide bigger
>> double-int (or wide-int) for this.  Let's call this abstraction
>> wide-int (as opposed to my suggested more piecemail double_sint,
>> double_uint).  You can perfectly model it ontop of the existing
>> double_int storage.
>>
>> As of providing larger "double-ints" - there is not much code left
>> (ok, quite an overstatement ;)) that relies on the implementation
>> detail of double-int containing exactly two HOST_WIDE_INTs.
>> The exact purpose of double-ints was to _hide_ this (previously
>> we only had routines like mul_double_with_sign which take
>> two HOST_WIDE_INT components).  Most code dealing with
>> the implementation detail is code interfacing with middle-end
>> routines that take a HOST_WIDE_INT argument (thus the
>> double_int_fits_hwi_p predicates) - even wide_int has to support
>> this kind of interfacing.
>>
>> So, after introducing wide_int that just wraps double_int and
>> changing all user code (hopefully all, I guess mostly all), we'd
>> tackle the issue that the size of double_int's is host dependent.
>> A simple solution is to make it's size dependent on a target macro
>> (yes, macro ...), so on a 32bit HWI host targeting a 64bit 'HWI' target
>> you'd simply have four HWIs in the 'double-int' storage (and
>> arithmetic needs to be generalized to support this).
>
> I just don't see why this is a good thing.  The constraints
> are different when storing integers and when operating on them.
> When operating on them, we want something that is easily constructed
> on the stack, so we can create temporary structures very cheaply,
> and can easily pass and return them.  We happen to know at GCC's
> compile time how big the biggest integer will ever be, so it makes
> sense for wide_int to be that wide.

I'm not arguing against this.  I'm just saying that the internal
representation will depend on the host - not the number of total
bits, but the number of pieces.

> But when storing integers we want something compact.  If your
> machine supports 256-bit integers, but the code you're compiling
> makes heavy use of 128-bit integers, why would you want to waste
> 128 of 256 bits on every stored integer?  Which is why even
> CONST_WIDE_INT doesn't have a fixed width.
>
> You seem to be arguing that the type used to store integers in the IR
> has to be same as the one that we use when performing compile-time
> arithmetic, but I think it's better to have an abstraction between
> the two.

Well, you don't want to pay the cost dividing 256bit numbers all
the time when most of your numbers are only 128bit.  So we don't
really want to perform compile-time arithmetic on the biggest
possible precision either.  Ideally, of course - at the moment
we have double-ints and what precision we internally use
is an implementation detail (once it is sufficient precision).

> So if you think a pair of HWIs continues to be a useful way of
> storing integers at the tree level, then we can easily continue
> to use a pair of HWIs there.

How do you store larger ints there then?  How is CONST_WIDE_INT
variable size?  Why can wide-int not be variable-size?

> Or if you'd prefer every tree integer
> to be the same width as a wide_int, we can do that too.  (I don't
> know what Kenny's tree patch does.)

Keenys patch truncates wide-ints to two HWIs in wide-int-to-tree
without any checking (I claimed it's a bug, Kenny says its a feature).

>  But the whole point of having
> wide_int as an abstraction is that most code _operating_ on integers
> doesn't care what the representation is.  It becomes much easier to
> change that representation to whatever gives the best performance.

Sure!  And I agree totally with this!  Just don't mix enlarging that thing
from double_int in the first round of implementation!

> Another advantage of abstracting away the storage type is that
> we could store things like an overflow flag in the wide_int
> (if that ever proves useful) without worrying about the impact
> on the tree and RTL footprint.

Sure.

We seem to be talking in circles.  You don't seem to want (or care)
about a common storage for tree, RTL and wide-int.  You seem to
care about that operate-on-wide-ints thing.  I am saying if you keep
double-ints as-is you create two similar things which should be one thing.

So, make double-int storage only.  Introduce wide-int and use that
everywhere we compute on double-ints.  Whether wide-int is variable-size
or not is an implementation detail (if it's not we simply ICE if you require
a too large wide-int).  Wheter IL storage is variable-size or not is an
implementation detail as well.

What I don't see is that the patch just introduces wide-int as type
to do compile-time math on in RTL.  It does more (the patch is large
and I didn't read it in detail).  It doesn't even try to address the same
on the tree level.  It doesn't address the fundamental issue of
double-int size being host dependent.

Instead it seems to focus on getting even larger constants "work"
(on RTL level only).

What I'd like to see is _just_ the wide-int abstraction, suitable to
replace both tree and RTL level compile-time math (without even
trying to conver all uses, that's just too much noise for a thorough
review).

Richard.

>> [The more complex solution makes double-int* just a pointer to the first
>> HWI, so it cannot be used without being "wrapped" in a wide-int
>> which implicitely would provide the number of HWIs pointed to
>> (yes, I think variable-sized wide-int storage is the ultimate way to go).]
>>
>> So ... can you possibly split the patch in a way that just does the
>> first thing (provide the high-level wrapper and make use of it from RTL)?
>> I don't see the reason to have both CONST_DOUBLE and CONST_WIDE,
>> in fact they should be the same given choice one for the 2nd step.
>> And you can of course trivially construct a wide-int from a CONST_INT
>> as well (given it has a mode).
>>
>> As of using a mode or precision in wide-int - for re-use on the tree level
>> you need a precision as not all precisions have a distinct mode.  As on
>> RTL you don't have a sign we probably don't want wide-ints to have a sign
>> but continue double-int-like to specify the sign as part of the operation
>> where it matters.
>
> Definitely agree that signedness is a property of the operation.
> (Saturation too IMO.)  I don't really mind about mode vs. precision.
>
> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 11:42                   ` Richard Guenther
@ 2012-10-05 12:26                     ` Richard Sandiford
  2012-10-05 12:39                       ` Richard Guenther
  2012-10-05 13:11                     ` Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2012-10-05 12:26 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Kenneth Zadeck, Mike Stump, gcc-patches

Richard Guenther <richard.guenther@gmail.com> writes:
> On Fri, Oct 5, 2012 at 1:24 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Guenther <richard.guenther@gmail.com> writes:
>>> The issue is that unlike RTL where we "construct" double-ints from
>>> CONST_INT/CONST_DOUBLE right now, tree has the double-int
>>> _embedded_.  That's why I say that the thing we embed in
>>> a CONST_WIDE_INT or a tree INTEGER_CST needs to be
>>> "bare metal", and that's what I would call wide-int.
>>
>> OK, but that's deliberately not what Kenny's patch calls "wide int".
>> The whole idea is that the "bare metal" thing we embed in a
>> CONST_WIDE_INT or tree isn't (and doesn't need to be) the same
>> as the type that we use to operate on integers.  That bare-metal
>> thing doesn't even have to have a fixed width.  (CONST_WIDE_INT
>> doesn't have a fixed width, it's only as big as the integer
>> needs it to be.)
>
> Ok, let's rephrase it this way then: the "bare metal" thing used
> for the storage should ideally be the same in the tree IL and the RTL
> IL _and_ the higher-level abstract wide-int.

Hmm, OK, that's a straight disagreement then.

>>> So to me wide-ints provide the higher-level abstraction ontop of
>>> double-ints (which would remain the storage entity).
>>>
>>> Such higher-level abstraction is very useful, also for double-ints and
>>> also on the tree level.  There is no requirement to provide bigger
>>> double-int (or wide-int) for this.  Let's call this abstraction
>>> wide-int (as opposed to my suggested more piecemail double_sint,
>>> double_uint).  You can perfectly model it ontop of the existing
>>> double_int storage.
>>>
>>> As of providing larger "double-ints" - there is not much code left
>>> (ok, quite an overstatement ;)) that relies on the implementation
>>> detail of double-int containing exactly two HOST_WIDE_INTs.
>>> The exact purpose of double-ints was to _hide_ this (previously
>>> we only had routines like mul_double_with_sign which take
>>> two HOST_WIDE_INT components).  Most code dealing with
>>> the implementation detail is code interfacing with middle-end
>>> routines that take a HOST_WIDE_INT argument (thus the
>>> double_int_fits_hwi_p predicates) - even wide_int has to support
>>> this kind of interfacing.
>>>
>>> So, after introducing wide_int that just wraps double_int and
>>> changing all user code (hopefully all, I guess mostly all), we'd
>>> tackle the issue that the size of double_int's is host dependent.
>>> A simple solution is to make it's size dependent on a target macro
>>> (yes, macro ...), so on a 32bit HWI host targeting a 64bit 'HWI' target
>>> you'd simply have four HWIs in the 'double-int' storage (and
>>> arithmetic needs to be generalized to support this).
>>
>> I just don't see why this is a good thing.  The constraints
>> are different when storing integers and when operating on them.
>> When operating on them, we want something that is easily constructed
>> on the stack, so we can create temporary structures very cheaply,
>> and can easily pass and return them.  We happen to know at GCC's
>> compile time how big the biggest integer will ever be, so it makes
>> sense for wide_int to be that wide.
>
> I'm not arguing against this.  I'm just saying that the internal
> representation will depend on the host - not the number of total
> bits, but the number of pieces.

Sure, but Kenny already has a macro to specify how many bits we need
(MAX_BITSIZE_MODE_ANY_INT).  We can certainly wrap:

  HOST_WIDE_INT val[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];

in a typedef if that's what you prefer.

>> But when storing integers we want something compact.  If your
>> machine supports 256-bit integers, but the code you're compiling
>> makes heavy use of 128-bit integers, why would you want to waste
>> 128 of 256 bits on every stored integer?  Which is why even
>> CONST_WIDE_INT doesn't have a fixed width.
>>
>> You seem to be arguing that the type used to store integers in the IR
>> has to be same as the one that we use when performing compile-time
>> arithmetic, but I think it's better to have an abstraction between
>> the two.
>
> Well, you don't want to pay the cost dividing 256bit numbers all
> the time when most of your numbers are only 128bit.  So we don't
> really want to perform compile-time arithmetic on the biggest
> possible precision either.

wide_int doesn't perform them in the biggest possible precision.
It performs them in the precision of the result.  It just happens
to have enough storage to cope with all possible precisions (because
the actual precision of the result is usually only known at GCC's runtime).

>> So if you think a pair of HWIs continues to be a useful way of
>> storing integers at the tree level, then we can easily continue
>> to use a pair of HWIs there.
>
> How do you store larger ints there then?

You'd need another tree code for wider integers.  I'm not saying that's
a good idea, I just wasn't sure if it's what you wanted.

> How is CONST_WIDE_INT variable size?

It's just the usual trailing variable-length array thing.

> Why can wide-int not be variable-size?

Because variable-length arrays are usually more expensive
than (still fairly small) fixed-length arrays when dealing
with temporaries.

>> Or if you'd prefer every tree integer
>> to be the same width as a wide_int, we can do that too.  (I don't
>> know what Kenny's tree patch does.)
>
> Keenys patch truncates wide-ints to two HWIs in wide-int-to-tree
> without any checking (I claimed it's a bug, Kenny says its a feature).

Only because he split the rtl and tree parts up.  By "Kenny's tree patch",
I meant the patch that he said he was going to send (part 4 as he called it).

Until then, we're not regressing at the tree level, and I think
the patch is a genuine RTL improvement on its own.

>> Another advantage of abstracting away the storage type is that
>> we could store things like an overflow flag in the wide_int
>> (if that ever proves useful) without worrying about the impact
>> on the tree and RTL footprint.
>
> Sure.
>
> We seem to be talking in circles.  You don't seem to want (or care)
> about a common storage for tree, RTL and wide-int.  You seem to
> care about that operate-on-wide-ints thing.  I am saying if you keep
> double-ints as-is you create two similar things which should be one thing.

The idea is to get rid of double_ints altogether.  They shouldn't have
any use once everything has been converted to wide_ints.

> So, make double-int storage only.

The idea was to treat them as legacy and get rid of them as soon
as we can.

> What I don't see is that the patch just introduces wide-int as type
> to do compile-time math on in RTL.  It does more (the patch is large
> and I didn't read it in detail).

Yeah, it introduces things like the CONST_SCALAR_INT_P abstraction.
But I actually find the patch easier to review like that, because both
changes are affecting the same kinds of place.

> It doesn't even try to address the same on the tree level.

Because as Kenny's already said, that's a separate patch.

> It doesn't address the fundamental issue of double-int size being host
> dependent.

Because the plan is to get rid of it :-)

* Trivial, but it has the wrong name.

* It has the wrong interface for general-precision arithmetic because
  it doesn't say how wide the value stored (or to be stored) in those
  HOST_WIDE_INTs actually is.  E.g. there's no such thing as an "X-bit
  add followed by an X-bit division".  You have to a "double_int-wide
  add", followed by a truncation/extension to X bits, followed by a
  "double_int-wide division", followed by another truncation/extension
  to X bits.  Which we don't do in RTL; we just assume or (occasionally)
  assert that we only use double_int for modes whose precisions are
  exactly 2 * HOST_BITS_PER_WIDE_INT.

* Using a fixed-length array of HOST_WIDE_INTs is too inflexible
  for size-conscious IRs, so just bumping its size probably isn't
  a good idea for them.  But having a fixed-length array does
  IMO make sense for temporaries.

* If we made it storage-only, it doesn't need all those operations.

Which is why I agree with Kenny that double_int as it exists today
isn't the right starting point.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 12:26                     ` Richard Sandiford
@ 2012-10-05 12:39                       ` Richard Guenther
  2012-10-05 13:11                         ` Richard Sandiford
  2012-10-05 13:49                         ` Richard Guenther
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Guenther @ 2012-10-05 12:39 UTC (permalink / raw)
  To: Richard Guenther, Kenneth Zadeck, Mike Stump, gcc-patches, rdsandiford

On Fri, Oct 5, 2012 at 2:26 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Guenther <richard.guenther@gmail.com> writes:
>> On Fri, Oct 5, 2012 at 1:24 PM, Richard Sandiford
>> <rdsandiford@googlemail.com> wrote:
>>> Richard Guenther <richard.guenther@gmail.com> writes:
>>>> The issue is that unlike RTL where we "construct" double-ints from
>>>> CONST_INT/CONST_DOUBLE right now, tree has the double-int
>>>> _embedded_.  That's why I say that the thing we embed in
>>>> a CONST_WIDE_INT or a tree INTEGER_CST needs to be
>>>> "bare metal", and that's what I would call wide-int.
>>>
>>> OK, but that's deliberately not what Kenny's patch calls "wide int".
>>> The whole idea is that the "bare metal" thing we embed in a
>>> CONST_WIDE_INT or tree isn't (and doesn't need to be) the same
>>> as the type that we use to operate on integers.  That bare-metal
>>> thing doesn't even have to have a fixed width.  (CONST_WIDE_INT
>>> doesn't have a fixed width, it's only as big as the integer
>>> needs it to be.)
>>
>> Ok, let's rephrase it this way then: the "bare metal" thing used
>> for the storage should ideally be the same in the tree IL and the RTL
>> IL _and_ the higher-level abstract wide-int.
>
> Hmm, OK, that's a straight disagreement then.
>
>>>> So to me wide-ints provide the higher-level abstraction ontop of
>>>> double-ints (which would remain the storage entity).
>>>>
>>>> Such higher-level abstraction is very useful, also for double-ints and
>>>> also on the tree level.  There is no requirement to provide bigger
>>>> double-int (or wide-int) for this.  Let's call this abstraction
>>>> wide-int (as opposed to my suggested more piecemail double_sint,
>>>> double_uint).  You can perfectly model it ontop of the existing
>>>> double_int storage.
>>>>
>>>> As of providing larger "double-ints" - there is not much code left
>>>> (ok, quite an overstatement ;)) that relies on the implementation
>>>> detail of double-int containing exactly two HOST_WIDE_INTs.
>>>> The exact purpose of double-ints was to _hide_ this (previously
>>>> we only had routines like mul_double_with_sign which take
>>>> two HOST_WIDE_INT components).  Most code dealing with
>>>> the implementation detail is code interfacing with middle-end
>>>> routines that take a HOST_WIDE_INT argument (thus the
>>>> double_int_fits_hwi_p predicates) - even wide_int has to support
>>>> this kind of interfacing.
>>>>
>>>> So, after introducing wide_int that just wraps double_int and
>>>> changing all user code (hopefully all, I guess mostly all), we'd
>>>> tackle the issue that the size of double_int's is host dependent.
>>>> A simple solution is to make it's size dependent on a target macro
>>>> (yes, macro ...), so on a 32bit HWI host targeting a 64bit 'HWI' target
>>>> you'd simply have four HWIs in the 'double-int' storage (and
>>>> arithmetic needs to be generalized to support this).
>>>
>>> I just don't see why this is a good thing.  The constraints
>>> are different when storing integers and when operating on them.
>>> When operating on them, we want something that is easily constructed
>>> on the stack, so we can create temporary structures very cheaply,
>>> and can easily pass and return them.  We happen to know at GCC's
>>> compile time how big the biggest integer will ever be, so it makes
>>> sense for wide_int to be that wide.
>>
>> I'm not arguing against this.  I'm just saying that the internal
>> representation will depend on the host - not the number of total
>> bits, but the number of pieces.
>
> Sure, but Kenny already has a macro to specify how many bits we need
> (MAX_BITSIZE_MODE_ANY_INT).  We can certainly wrap:
>
>   HOST_WIDE_INT val[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
>
> in a typedef if that's what you prefer.

I'd prefer it to be initially double_int, and later "fixed" to double_int
with a member like the above.  Possibly renamed as well.

>>> But when storing integers we want something compact.  If your
>>> machine supports 256-bit integers, but the code you're compiling
>>> makes heavy use of 128-bit integers, why would you want to waste
>>> 128 of 256 bits on every stored integer?  Which is why even
>>> CONST_WIDE_INT doesn't have a fixed width.
>>>
>>> You seem to be arguing that the type used to store integers in the IR
>>> has to be same as the one that we use when performing compile-time
>>> arithmetic, but I think it's better to have an abstraction between
>>> the two.
>>
>> Well, you don't want to pay the cost dividing 256bit numbers all
>> the time when most of your numbers are only 128bit.  So we don't
>> really want to perform compile-time arithmetic on the biggest
>> possible precision either.
>
> wide_int doesn't perform them in the biggest possible precision.
> It performs them in the precision of the result.  It just happens
> to have enough storage to cope with all possible precisions (because
> the actual precision of the result is usually only known at GCC's runtime).
>
>>> So if you think a pair of HWIs continues to be a useful way of
>>> storing integers at the tree level, then we can easily continue
>>> to use a pair of HWIs there.
>>
>> How do you store larger ints there then?
>
> You'd need another tree code for wider integers.  I'm not saying that's
> a good idea, I just wasn't sure if it's what you wanted.

Uh, ok.

>> How is CONST_WIDE_INT variable size?
>
> It's just the usual trailing variable-length array thing.

Good.  Do you get rid of CONST_DOUBLE (for integers) at the same time?

>> Why can wide-int not be variable-size?
>
> Because variable-length arrays are usually more expensive
> than (still fairly small) fixed-length arrays when dealing
> with temporaries.

which is why I'd have made it a template (but I admit I didn't fully
investigate all issues).  Something like

template <unsigned bits>  (or bytes?)
struct wide_int {
  unsigned short precision;
  HOST_WIDE_INT val[(bits + HOST_BITS_PER_WIDE_INT - 1) /
HOST_BITS_PER_WIDE_INT];
};

so it would not be variable-size at compile-time but we'd be able
to constrain its maximum size.  That's important for things like
CCP which keep a lattice of ints and maybe do not want to care
about tracking your new 4096-bit integers.

But maybe we don't really care.

>>> Or if you'd prefer every tree integer
>>> to be the same width as a wide_int, we can do that too.  (I don't
>>> know what Kenny's tree patch does.)
>>
>> Keenys patch truncates wide-ints to two HWIs in wide-int-to-tree
>> without any checking (I claimed it's a bug, Kenny says its a feature).
>
> Only because he split the rtl and tree parts up.  By "Kenny's tree patch",
> I meant the patch that he said he was going to send (part 4 as he called it).
>
> Until then, we're not regressing at the tree level, and I think
> the patch is a genuine RTL improvement on its own.
>
>>> Another advantage of abstracting away the storage type is that
>>> we could store things like an overflow flag in the wide_int
>>> (if that ever proves useful) without worrying about the impact
>>> on the tree and RTL footprint.
>>
>> Sure.
>>
>> We seem to be talking in circles.  You don't seem to want (or care)
>> about a common storage for tree, RTL and wide-int.  You seem to
>> care about that operate-on-wide-ints thing.  I am saying if you keep
>> double-ints as-is you create two similar things which should be one thing.
>
> The idea is to get rid of double_ints altogether.  They shouldn't have
> any use once everything has been converted to wide_ints.
>
>> So, make double-int storage only.
>
> The idea was to treat them as legacy and get rid of them as soon
> as we can.
>
>> What I don't see is that the patch just introduces wide-int as type
>> to do compile-time math on in RTL.  It does more (the patch is large
>> and I didn't read it in detail).
>
> Yeah, it introduces things like the CONST_SCALAR_INT_P abstraction.
> But I actually find the patch easier to review like that, because both
> changes are affecting the same kinds of place.
>
>> It doesn't even try to address the same on the tree level.
>
> Because as Kenny's already said, that's a separate patch.
>
>> It doesn't address the fundamental issue of double-int size being host
>> dependent.
>
> Because the plan is to get rid of it :-)
>
> * Trivial, but it has the wrong name.
>
> * It has the wrong interface for general-precision arithmetic because
>   it doesn't say how wide the value stored (or to be stored) in those
>   HOST_WIDE_INTs actually is.  E.g. there's no such thing as an "X-bit
>   add followed by an X-bit division".  You have to a "double_int-wide
>   add", followed by a truncation/extension to X bits, followed by a
>   "double_int-wide division", followed by another truncation/extension
>   to X bits.  Which we don't do in RTL; we just assume or (occasionally)
>   assert that we only use double_int for modes whose precisions are
>   exactly 2 * HOST_BITS_PER_WIDE_INT.
>
> * Using a fixed-length array of HOST_WIDE_INTs is too inflexible
>   for size-conscious IRs, so just bumping its size probably isn't
>   a good idea for them.  But having a fixed-length array does
>   IMO make sense for temporaries.
>
> * If we made it storage-only, it doesn't need all those operations.
>
> Which is why I agree with Kenny that double_int as it exists today
> isn't the right starting point.

Ok, I see where you are going.  Let me look at the patch again.

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 11:42                   ` Richard Guenther
  2012-10-05 12:26                     ` Richard Sandiford
@ 2012-10-05 13:11                     ` Kenneth Zadeck
  1 sibling, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-05 13:11 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Mike Stump, gcc-patches, rdsandiford

richi,

let me address a bunch of issues that are randomly spread thru the thread.

1) unlike the double int's current relationship to int cst, we do not 
currently wrap a wide-int into an CONST_WIDE_INT nor (in the patch that 
you have not seen) do we wrap a wide-int into the int cst.    wide-ints 
are designed to be short lived.   With the exception of the vrp pass, 
they are almost always allocated on the stack and thrown away 
quickly.    That way we can afford to grab a big buffer and play with it.

The rep that lives in the CONST_WIDE_INT and the int cst is a garbage 
collected array of HWIs that is only large enough to hold the actual 
value.   and it is almost always an array of length 1. This saves space 
and works because they are immutable.

This means that there is almost no storage bloat by going with this 
representation no matter how large the widest integer is on the platform.

2) wide-int is really just a generalized version of double-int. The abi 
is different because it does not have all of those calls that take two 
HWIs explicitly and because i was building it all at once LOOKING BOTH 
AT THE TREE AND RTL levels, it has a richer set of calls.   Aside from 
it carrying a mode around that it uses for precision and bitsize, it is 
really bare metal.   My problem is that i am still working on getting 
the tree level stuff working, and phase 1 is closing soon and i wanted 
to get my foot in the door.

3) I think that everyone agrees that having CONST_DOUBLE and CONST_INT 
not carrying around modes was a big mistake.   I toyed with the idea for 
a nanosecond of fixing that along with this, but as you point out the 
patches are already way to large and it would have meant that the burden 
on converting the ports would be larger.   BUT, as the note in the 
original email said, this patch moves significantly in the direction of 
being able to have a mode for the integers at the rtl level.    It does 
this by no longer storing integer values in CONST_DOUBLEs so there is no 
longer the test of VOIDmode to see what the CONST_DOUBLE contains.    
Also the patch contains a significant number of changes (in the machine 
independent rtl code) to the constructors that carry the mode, rather 
than using GENINT.

4) Having the mode (or at least the precision and bitsize) is crutial 
for the performance of wide-int.   All of the interesting functions have 
quick out tests to use the bare metal operators if the precision fits a 
HWI.  This way, 99% of the time, we are just doing c operators with a 
simple check.

kenny


On 10/05/2012 07:41 AM, Richard Guenther wrote:
> On Fri, Oct 5, 2012 at 1:24 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Guenther <richard.guenther@gmail.com> writes:
>>> On Fri, Oct 5, 2012 at 11:55 AM, Richard Sandiford
>>> <rdsandiford@googlemail.com> wrote:
>>>> Richard Guenther <richard.guenther@gmail.com> writes:
>>>>>> As far as the wide_ints recording a mode or precision goes: we're in
>>>>>> the "lucky" position of having tried both options.  Trees record the
>>>>>> type (and thus precision) of all compile-time integer constants.
>>>>>> RTL doesn't.  And the RTL way is a right pain.  It leads to interfaces
>>>>>> in which rtx arguments often have to be accompanied by a mode.  And it
>>>>>> leads to clunky differences like those between simplify_unary_operation
>>>>>> (which takes two mode arguments) and simplify_binary_operation
>>>>>> (which with our current set of binary operations requires only one).
>>>>> But the issue here is not that double_int doesn't record a mode
>>>>> or precision (or a sign).  The issue is that CONST_DOUBLE and CONST_INT
>>>>> don't!  The _tree_ INTEGER_CST contains of a type and a double-int.
>>>>> I see double-int (and the proposed wide-int) as a common building-block
>>>>> used for kind of "arbitrary precision" (as far as the target needs) integer
>>>>> constants on both tree and RTL.  And having a common worker implementation
>>>>> requires it to operate on something different than tree types or RTL mode
>>>>> plus signedness.
>>>>>
>>>>>> To put it another way: every wide_int operation needs to know
>>>>>> the precision of its arguments and the precision of its result.
>>>>> That's not true.  Every tree or RTL operation does, not every
>>>>> wide_int operation.  double_int's are just twos-complement numbers
>>>>> of precision 2 * HOST_BITS_PER_WIDE_INT.  wide_int's should
>>>>> be just twos-complement numbers of precision len *
>>>>> WHATEVER_HOST_COMPONENT_TYPE_IS_SUITABLE_FOR_A_FAST_IMPLEMENTATION.
>>>>> Operations on double_int and wide_int are bare-metal,
>>>>> in nearly all of the times you should use routines that do
>>>>> proper sign-/zero-extending to a possibly smaller precision.  When
>>>>> using bare-metal you are supposed to do that yourself.
>>>>>
>>>>> Which is why I was suggesting to add double_sint, double_uint,
>>>>> double_sintp (with precision), etc., wrappers and operations.
>>>>>
>>>>>> Not storing the precision in the wide_int is putting the onus
>>>>>> on the caller to keep track of the precision separately.
>>>>> But that's a matter of providing something high-level ontop of
>>>>> the bare-metal double-int/wide-int (something shared between
>>>>> RTL and trees).  Duplicating information in the bare-metal
>>>>> doesn't make sense (and no, INTEGER_CSTs on the tree level
>>>>> are _not_ short-lived, and how can a double-int make sense on
>>>>> the tree level when you say it doesn't make sense on the RTL level?)
>>>> I think we're talking at cross purposes here.  To the extent that
>>>> I'm not really sure where to begin. :-)  Just in case this is it:
>>>> the idea is that wide_int is the type used to _process_ integers.
>>>> It is not suppoed to be the type used to store integers in the IRs.
>>>> The way trees store integers and the way that RTL stores integers
>>>> are up to them.  For RTL the idea is that we continue to store integers
>>>> that happen to fit into a HWI as a CONST_INT (regardless of the size of
>>>> the CONST_INT's context-determined mode).  Wider integers are stored
>>>> as a CONST_DOUBLE (for unconverted targets) or a CONST_WIDE_INT
>>>> (for converted targets).  None of the three use the wide_int type;
>>>> they use more compact representations instead.  And as Kenny says,
>>>> using CONST_INT continues to be an important way of reducing the
>>>> IR footprint.
>>>>
>>>> Whenever we want to do something interesting with the integers,
>>>> we construct a wide_int for them and use the same processing code
>>>> for all three rtx types.  This avoids having the separate single-HWI
>>>> and double-HWI paths that we have now.  It also copes naturally with
>>>> cases where we start out with single-HWI values but end up with wider
>>>> ones.
>>>>
>>>> But the operations that we do on these wide_ints will all be to a mode
>>>> or precision.  Shifts of QImode integers are different from shifts of
>>>> HImode integers, etc.
>>>>
>>>> If you knew all that already (you probably did) and I've completely
>>>> missed the point, please say so. :-)
>>>>
>>>> I'm not sure what you mean by "bare metal".
>>> The issue is that unlike RTL where we "construct" double-ints from
>>> CONST_INT/CONST_DOUBLE right now, tree has the double-int
>>> _embedded_.  That's why I say that the thing we embed in
>>> a CONST_WIDE_INT or a tree INTEGER_CST needs to be
>>> "bare metal", and that's what I would call wide-int.
>> OK, but that's deliberately not what Kenny's patch calls "wide int".
>> The whole idea is that the "bare metal" thing we embed in a
>> CONST_WIDE_INT or tree isn't (and doesn't need to be) the same
>> as the type that we use to operate on integers.  That bare-metal
>> thing doesn't even have to have a fixed width.  (CONST_WIDE_INT
>> doesn't have a fixed width, it's only as big as the integer
>> needs it to be.)
> Ok, let's rephrase it this way then: the "bare metal" thing used
> for the storage should ideally be the same in the tree IL and the RTL
> IL _and_ the higher-level abstract wide-int.
>
>>> So to me wide-ints provide the higher-level abstraction ontop of
>>> double-ints (which would remain the storage entity).
>>>
>>> Such higher-level abstraction is very useful, also for double-ints and
>>> also on the tree level.  There is no requirement to provide bigger
>>> double-int (or wide-int) for this.  Let's call this abstraction
>>> wide-int (as opposed to my suggested more piecemail double_sint,
>>> double_uint).  You can perfectly model it ontop of the existing
>>> double_int storage.
>>>
>>> As of providing larger "double-ints" - there is not much code left
>>> (ok, quite an overstatement ;)) that relies on the implementation
>>> detail of double-int containing exactly two HOST_WIDE_INTs.
>>> The exact purpose of double-ints was to _hide_ this (previously
>>> we only had routines like mul_double_with_sign which take
>>> two HOST_WIDE_INT components).  Most code dealing with
>>> the implementation detail is code interfacing with middle-end
>>> routines that take a HOST_WIDE_INT argument (thus the
>>> double_int_fits_hwi_p predicates) - even wide_int has to support
>>> this kind of interfacing.
>>>
>>> So, after introducing wide_int that just wraps double_int and
>>> changing all user code (hopefully all, I guess mostly all), we'd
>>> tackle the issue that the size of double_int's is host dependent.
>>> A simple solution is to make it's size dependent on a target macro
>>> (yes, macro ...), so on a 32bit HWI host targeting a 64bit 'HWI' target
>>> you'd simply have four HWIs in the 'double-int' storage (and
>>> arithmetic needs to be generalized to support this).
>> I just don't see why this is a good thing.  The constraints
>> are different when storing integers and when operating on them.
>> When operating on them, we want something that is easily constructed
>> on the stack, so we can create temporary structures very cheaply,
>> and can easily pass and return them.  We happen to know at GCC's
>> compile time how big the biggest integer will ever be, so it makes
>> sense for wide_int to be that wide.
> I'm not arguing against this.  I'm just saying that the internal
> representation will depend on the host - not the number of total
> bits, but the number of pieces.
>
>> But when storing integers we want something compact.  If your
>> machine supports 256-bit integers, but the code you're compiling
>> makes heavy use of 128-bit integers, why would you want to waste
>> 128 of 256 bits on every stored integer?  Which is why even
>> CONST_WIDE_INT doesn't have a fixed width.
>>
>> You seem to be arguing that the type used to store integers in the IR
>> has to be same as the one that we use when performing compile-time
>> arithmetic, but I think it's better to have an abstraction between
>> the two.
> Well, you don't want to pay the cost dividing 256bit numbers all
> the time when most of your numbers are only 128bit.  So we don't
> really want to perform compile-time arithmetic on the biggest
> possible precision either.  Ideally, of course - at the moment
> we have double-ints and what precision we internally use
> is an implementation detail (once it is sufficient precision).
>
>> So if you think a pair of HWIs continues to be a useful way of
>> storing integers at the tree level, then we can easily continue
>> to use a pair of HWIs there.
> How do you store larger ints there then?  How is CONST_WIDE_INT
> variable size?  Why can wide-int not be variable-size?
>
>> Or if you'd prefer every tree integer
>> to be the same width as a wide_int, we can do that too.  (I don't
>> know what Kenny's tree patch does.)
> Keenys patch truncates wide-ints to two HWIs in wide-int-to-tree
> without any checking (I claimed it's a bug, Kenny says its a feature).
>
>>   But the whole point of having
>> wide_int as an abstraction is that most code _operating_ on integers
>> doesn't care what the representation is.  It becomes much easier to
>> change that representation to whatever gives the best performance.
> Sure!  And I agree totally with this!  Just don't mix enlarging that thing
> from double_int in the first round of implementation!
>
>> Another advantage of abstracting away the storage type is that
>> we could store things like an overflow flag in the wide_int
>> (if that ever proves useful) without worrying about the impact
>> on the tree and RTL footprint.
> Sure.
>
> We seem to be talking in circles.  You don't seem to want (or care)
> about a common storage for tree, RTL and wide-int.  You seem to
> care about that operate-on-wide-ints thing.  I am saying if you keep
> double-ints as-is you create two similar things which should be one thing.
>
> So, make double-int storage only.  Introduce wide-int and use that
> everywhere we compute on double-ints.  Whether wide-int is variable-size
> or not is an implementation detail (if it's not we simply ICE if you require
> a too large wide-int).  Wheter IL storage is variable-size or not is an
> implementation detail as well.
>
> What I don't see is that the patch just introduces wide-int as type
> to do compile-time math on in RTL.  It does more (the patch is large
> and I didn't read it in detail).  It doesn't even try to address the same
> on the tree level.  It doesn't address the fundamental issue of
> double-int size being host dependent.
>
> Instead it seems to focus on getting even larger constants "work"
> (on RTL level only).
>
> What I'd like to see is _just_ the wide-int abstraction, suitable to
> replace both tree and RTL level compile-time math (without even
> trying to conver all uses, that's just too much noise for a thorough
> review).
>
> Richard.
>
>>> [The more complex solution makes double-int* just a pointer to the first
>>> HWI, so it cannot be used without being "wrapped" in a wide-int
>>> which implicitely would provide the number of HWIs pointed to
>>> (yes, I think variable-sized wide-int storage is the ultimate way to go).]
>>>
>>> So ... can you possibly split the patch in a way that just does the
>>> first thing (provide the high-level wrapper and make use of it from RTL)?
>>> I don't see the reason to have both CONST_DOUBLE and CONST_WIDE,
>>> in fact they should be the same given choice one for the 2nd step.
>>> And you can of course trivially construct a wide-int from a CONST_INT
>>> as well (given it has a mode).
>>>
>>> As of using a mode or precision in wide-int - for re-use on the tree level
>>> you need a precision as not all precisions have a distinct mode.  As on
>>> RTL you don't have a sign we probably don't want wide-ints to have a sign
>>> but continue double-int-like to specify the sign as part of the operation
>>> where it matters.
>> Definitely agree that signedness is a property of the operation.
>> (Saturation too IMO.)  I don't really mind about mode vs. precision.
>>
>> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 12:39                       ` Richard Guenther
@ 2012-10-05 13:11                         ` Richard Sandiford
  2012-10-05 13:18                           ` Richard Sandiford
  2012-10-05 13:49                         ` Richard Guenther
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2012-10-05 13:11 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Kenneth Zadeck, Mike Stump, gcc-patches

Richard Guenther <richard.guenther@gmail.com> writes:
> On Fri, Oct 5, 2012 at 2:26 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Guenther <richard.guenther@gmail.com> writes:
>>> On Fri, Oct 5, 2012 at 1:24 PM, Richard Sandiford
>>> <rdsandiford@googlemail.com> wrote:
>>>> Richard Guenther <richard.guenther@gmail.com> writes:
>>>>> The issue is that unlike RTL where we "construct" double-ints from
>>>>> CONST_INT/CONST_DOUBLE right now, tree has the double-int
>>>>> _embedded_.  That's why I say that the thing we embed in
>>>>> a CONST_WIDE_INT or a tree INTEGER_CST needs to be
>>>>> "bare metal", and that's what I would call wide-int.
>>>>
>>>> OK, but that's deliberately not what Kenny's patch calls "wide int".
>>>> The whole idea is that the "bare metal" thing we embed in a
>>>> CONST_WIDE_INT or tree isn't (and doesn't need to be) the same
>>>> as the type that we use to operate on integers.  That bare-metal
>>>> thing doesn't even have to have a fixed width.  (CONST_WIDE_INT
>>>> doesn't have a fixed width, it's only as big as the integer
>>>> needs it to be.)
>>>
>>> Ok, let's rephrase it this way then: the "bare metal" thing used
>>> for the storage should ideally be the same in the tree IL and the RTL
>>> IL _and_ the higher-level abstract wide-int.
>>
>> Hmm, OK, that's a straight disagreement then.
>>
>>>>> So to me wide-ints provide the higher-level abstraction ontop of
>>>>> double-ints (which would remain the storage entity).
>>>>>
>>>>> Such higher-level abstraction is very useful, also for double-ints and
>>>>> also on the tree level.  There is no requirement to provide bigger
>>>>> double-int (or wide-int) for this.  Let's call this abstraction
>>>>> wide-int (as opposed to my suggested more piecemail double_sint,
>>>>> double_uint).  You can perfectly model it ontop of the existing
>>>>> double_int storage.
>>>>>
>>>>> As of providing larger "double-ints" - there is not much code left
>>>>> (ok, quite an overstatement ;)) that relies on the implementation
>>>>> detail of double-int containing exactly two HOST_WIDE_INTs.
>>>>> The exact purpose of double-ints was to _hide_ this (previously
>>>>> we only had routines like mul_double_with_sign which take
>>>>> two HOST_WIDE_INT components).  Most code dealing with
>>>>> the implementation detail is code interfacing with middle-end
>>>>> routines that take a HOST_WIDE_INT argument (thus the
>>>>> double_int_fits_hwi_p predicates) - even wide_int has to support
>>>>> this kind of interfacing.
>>>>>
>>>>> So, after introducing wide_int that just wraps double_int and
>>>>> changing all user code (hopefully all, I guess mostly all), we'd
>>>>> tackle the issue that the size of double_int's is host dependent.
>>>>> A simple solution is to make it's size dependent on a target macro
>>>>> (yes, macro ...), so on a 32bit HWI host targeting a 64bit 'HWI' target
>>>>> you'd simply have four HWIs in the 'double-int' storage (and
>>>>> arithmetic needs to be generalized to support this).
>>>>
>>>> I just don't see why this is a good thing.  The constraints
>>>> are different when storing integers and when operating on them.
>>>> When operating on them, we want something that is easily constructed
>>>> on the stack, so we can create temporary structures very cheaply,
>>>> and can easily pass and return them.  We happen to know at GCC's
>>>> compile time how big the biggest integer will ever be, so it makes
>>>> sense for wide_int to be that wide.
>>>
>>> I'm not arguing against this.  I'm just saying that the internal
>>> representation will depend on the host - not the number of total
>>> bits, but the number of pieces.
>>
>> Sure, but Kenny already has a macro to specify how many bits we need
>> (MAX_BITSIZE_MODE_ANY_INT).  We can certainly wrap:
>>
>>   HOST_WIDE_INT val[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
>>
>> in a typedef if that's what you prefer.
>
> I'd prefer it to be initially double_int, and later "fixed" to double_int
> with a member like the above.  Possibly renamed as well.

I'd like to avoid that.  The current double_int code really isn't useful
to the patch.  double_int doesn't have the right representation because
it uses a low/high pair (of slightly different types) rather than a
parameterised array.  The operators don't have the right interface,
for the reasons I described later.  They don't have the right
implementation because they're specific to HWI pairs rather than
parameterised based on the number of HWIs.  Once you change the name,
the internal representation, the operator interface, and the operator
implementation, there isn't a lot left to keep.

>>> How is CONST_WIDE_INT variable size?
>>
>> It's just the usual trailing variable-length array thing.
>
> Good.  Do you get rid of CONST_DOUBLE (for integers) at the same time?

Yeah.  I initially thought it might be OK to keep them and have
CONST_INT, integer CONST_DOUBLEs and CONST_WIDE_INT alongside
each other.  (The way the patch is structured means that the
choice of whether to keep integer CONST_DOUBLEs can be changed
very easily.)  But Kenny convinced me it was a bad idea.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 13:11                         ` Richard Sandiford
@ 2012-10-05 13:18                           ` Richard Sandiford
  2012-10-05 13:53                             ` Richard Guenther
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2012-10-05 13:18 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Kenneth Zadeck, Mike Stump, gcc-patches

Richard Sandiford <rdsandiford@googlemail.com> writes:
>>>> How is CONST_WIDE_INT variable size?
>>>
>>> It's just the usual trailing variable-length array thing.
>>
>> Good.  Do you get rid of CONST_DOUBLE (for integers) at the same time?
>
> Yeah.  I initially thought it might be OK to keep them and have
> CONST_INT, integer CONST_DOUBLEs and CONST_WIDE_INT alongside
> each other.  (The way the patch is structured means that the
> choice of whether to keep integer CONST_DOUBLEs can be changed
> very easily.)  But Kenny convinced me it was a bad idea.

Sorry to follow up on myself, but to clarify: I was talking about
converted targets here.  (As in, I originally thought even converted
targets could continue to use integer CONST_DOUBLEs.)

Unconverted targets continue to use CONST_DOUBLE.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 12:39                       ` Richard Guenther
  2012-10-05 13:11                         ` Richard Sandiford
@ 2012-10-05 13:49                         ` Richard Guenther
  2012-10-05 16:34                           ` Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Guenther @ 2012-10-05 13:49 UTC (permalink / raw)
  To: Richard Guenther, Kenneth Zadeck, Mike Stump, gcc-patches, rdsandiford

On Fri, Oct 5, 2012 at 2:39 PM, Richard Guenther
<richard.guenther@gmail.com> wrote:
>
> Ok, I see where you are going.  Let me look at the patch again.

* The introduction and use of CONST_SCALAR_INT_P could be split out
  (obvious and good)

* DEF_RTL_EXPR(CONST_WIDE_INT, "const_wide_int", "", RTX_CONST_OBJ)
  defining that new RTX is orthogonal to providing the wide_int abstraction
  for operating on CONST_INT and CONST_DOUBLE, right?

@@ -144,6 +144,7 @@ static bool
 prefer_and_bit_test (enum machine_mode mode, int bitnum)
 {
   bool speed_p;
+  wide_int mask = wide_int::set_bit_in_zero (bitnum, mode);

set_bit_in_zero ... why use this instead of
wide_int::zero (mode).set_bit (bitnum) that would match the old
double_int_zero.set_bit interface and be more composed of primitives?

   if (and_test == 0)
     {
@@ -164,8 +165,7 @@ prefer_and_bit_test (enum machine_mode m
     }

   /* Fill in the integers.  */
-  XEXP (and_test, 1)
-    = immed_double_int_const (double_int_zero.set_bit (bitnum), mode);
+  XEXP (and_test, 1) = immed_wide_int_const (mask);

I suppose immed_wide_int_const may create a CONST_INT, a CONST_DOUBLE
or a CONST_WIDE_INT?

+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns 1 if OP is an operand that is a CONST_INT or CONST_WIDE_INT.  */
+int
+const_scalar_int_operand (rtx op, enum machine_mode mode)
+{

why is it necessary to condition anything on TARGET_SUPPORTS_WIDE_INT?
It seems testing/compile coverage of this code will be bad ...

Can't you simply map CONST_WIDE_INT to CONST_DOUBLE for targets
not supporting CONST_WIDE_INT (what does it mean to "support"
CONST_WIDE_INT?  Does a target that supports CONST_WIDE_INT no
longer use CONST_DOUBLEs for integers?)

+  if (!CONST_WIDE_INT_P (op))
+    return 0;

hm, that doesn't match the comment (CONST_INT is supposed to return 1 as well).
The comment doesn't really tell what the function does it seems,

+      int prec = GET_MODE_PRECISION (mode);
+      int bitsize = GET_MODE_BITSIZE (mode);
+
+      if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
+       return 0;

it's mode argument is not documented.  And this doesn't even try to see if
the constant would fit the mode anyway (like if it's zero).  Not sure what
the function is for.

+       {
+         /* Multiword partial int.  */
+         HOST_WIDE_INT x
+           = CONST_WIDE_INT_ELT (op, CONST_WIDE_INT_NUNITS (op) - 1);
+         return (wide_int::sext (x, prec & (HOST_BITS_PER_WIDE_INT - 1))
+                 == x);

err - so now we have wide_int with a mode but we pass in another mode
and see if they have the same value?  Same value as-in signed value?
Which probably is why you need to rule out different size constants above?
Because you don't know whether to sign or zero extend?


+/* Returns 1 if OP is an operand that is a CONST_WIDE_INT.  */
+int
+const_wide_int_operand (rtx op, enum machine_mode mode)
+{

similar comments, common code should be factored out at least.
Instead of conditioning a whole set of new function on supports-wide-int
please add cases to the existing functions to avoid diverging in pieces
that both kind of targets support.

@@ -2599,7 +2678,7 @@ constrain_operands (int strict)
                break;

              case 'n':
-               if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+               if (CONST_SCALAR_INT_P (op))
                  win = 1;

factoring out this changes would really make the patch less noisy.

skipping to rtl.h bits

+struct GTY((variable_size)) hwivec_def {
+  int num_elem;                /* number of elements */
+  HOST_WIDE_INT elem[1];
+};

num_elem seems redundant and computable from GET_MODE_SIZE.
Or do you want to optimize encoding like for CONST_INT (and unlike
CONST_DOUBLE)?  I doubt the above packs nicely into rtx_def?
A general issue of it though - we waste 32bits on 64bit hosts in
rtx_def between the bits and the union.  Perfect place for num_elem
(if you really need it) and avoids another 4 byte hole.  Similar issue
exists in rtvec_def.

back to where I was

@@ -645,6 +673,10 @@ iterative_hash_rtx (const_rtx x, hashval
       return iterative_hash_object (i, hash);
     case CONST_INT:
       return iterative_hash_object (INTVAL (x), hash);
+    case CONST_WIDE_INT:
+      for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+       hash = iterative_hash_object (CONST_WIDE_INT_ELT (x, i), hash);
+      return hash;

I see CONST_DOUBLEs value is not hashed.  Why hash wide-ints value?

Seeing

+#define HWI_GET_NUM_ELEM(HWIVEC)       ((HWIVEC)->num_elem)
+#define HWI_PUT_NUM_ELEM(HWIVEC, NUM)  ((HWIVEC)->num_elem = (NUM))

skipping to

+#if TARGET_SUPPORTS_WIDE_INT
+  {
+    rtx value = const_wide_int_alloc (len);
+    unsigned int i;
+
+    /* It is so tempting to just put the mode in here.  Must control
+       myself ... */
+    PUT_MODE (value, VOIDmode);
+    HWI_PUT_NUM_ELEM (CONST_WIDE_INT_VEC (value), len);

why is NUM_ELEM not set in const_wide_int_alloc, and only there?

+extern rtx rtx_alloc_stat_v (RTX_CODE MEM_STAT_DECL, int);
+#define rtx_alloc_v(c, SZ) rtx_alloc_stat_v (c MEM_STAT_INFO, SZ)
+#define const_wide_int_alloc(NWORDS)                           \
+  rtx_alloc_v (CONST_WIDE_INT,                                 \
+              (sizeof (struct hwivec_def)                      \
+               + ((NWORDS)-1) * sizeof (HOST_WIDE_INT)))       \

because it's a macro(?).  Ugh.

I see CONST_DOUBLE for ints and CONST_WIDE_INT for ints use
is mutually exclusive.  Good.  What's the issue with converting targets?
Just retain the existing 2 * HWI limit by default.

+#if TARGET_SUPPORTS_WIDE_INT
+
+/* Match CONST_*s that can represent compile-time constant integers.  */
+#define CASE_CONST_SCALAR_INT \
+   case CONST_INT: \
+   case CONST_WIDE_INT
+

I regard this abstraction is mostly because the transition is not finished.
Not sure if seeing CASE_CONST_SCALAR_INT, CASE_CONST_UNIQUE (?),
CASE_CONST_ANY adds more to the confusion than spelling out all of them.
Isn't there sth like a tree-code-class for RTXen?  That would catch
CASE_CONST_ANY, no?

@@ -3081,6 +3081,8 @@ commutative_operand_precedence (rtx op)
   /* Constants always come the second operand.  Prefer "nice" constants.  */
   if (code == CONST_INT)
     return -8;
+  if (code == CONST_WIDE_INT)
+    return -8;
   if (code == CONST_DOUBLE)
     return -7;
   if (code == CONST_FIXED)

I think it should be the same as CONST_DOUBLE which it "replaces".
Likewise below, that avoids code generation changes (which there should
be none for a target that is converted, right?).

@@ -5351,6 +5355,20 @@ split_double (rtx value, rtx *first, rtx
            }
        }
     }
+  else if (GET_CODE (value) == CONST_WIDE_INT)
+    {
+      gcc_assert (CONST_WIDE_INT_NUNITS (value) == 2);
+      if (WORDS_BIG_ENDIAN)
+       {
+         *first = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+         *second = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+       }
+      else
+       {
+         *first = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+         *second = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+       }
+    }

scary ;)

Index: gcc/sched-vis.c
===================================================================
--- gcc/sched-vis.c     (revision 191978)
+++ gcc/sched-vis.c     (working copy)
@@ -444,14 +444,31 @@ print_value (char *buf, const_rtx x, int
...
     case CONST_DOUBLE:
-      if (FLOAT_MODE_P (GET_MODE (x)))
-       real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1);
-      else
+     if (TARGET_SUPPORTS_WIDE_INT == 0 && !FLOAT_MODE_P (GET_MODE (x)))
        sprintf (t,
                 "<" HOST_WIDE_INT_PRINT_HEX "," HOST_WIDE_INT_PRINT_HEX ">",
                 (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x),
                 (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x));
+      else
+       real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1);
       cur = safe_concat (buf, cur, t);
       break;

I don't see that this hunk is needed?  In fact it's more confusing this way.

+/* If the target supports integers that are wider than two
+   HOST_WIDE_INTs on the host compiler, then the target should define
+   TARGET_SUPPORTS_WIDE_INT and make the appropriate fixups.
+   Otherwise the compiler really is not robust.  */
+#ifndef TARGET_SUPPORTS_WIDE_INT
+#define TARGET_SUPPORTS_WIDE_INT 0
+#endif

I wonder what are the appropriate fixups?

-/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
-   GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
+/* Return a CONST_INT, CONST_WIDE_INT, or CONST_DOUBLE corresponding
+   to target reading GET_MODE_BITSIZE (MODE) bits from string constant
+   STR.  */

maybe being less specific in this kind of comments and just refering to
RTX integer constants would be better?

... skip ...

Index: gcc/hwint.c
===================================================================
--- gcc/hwint.c (revision 191978)
+++ gcc/hwint.c (working copy)
@@ -112,6 +112,29 @@ ffs_hwi (unsigned HOST_WIDE_INT x)
 int
 popcount_hwi (unsigned HOST_WIDE_INT x)
 {
+  /* Compute the popcount of a HWI using the algorithm from
+     Hacker's Delight.  */
+#if HOST_BITS_PER_WIDE_INT == 32

separate patch please.  With a rationale.

...

+/* Constructs tree in type TYPE from with value given by CST.  Signedness
+   of CST is assumed to be the same as the signedness of TYPE.  */
+
+tree
+wide_int_to_tree (tree type, const wide_int &cst)
+{
+  wide_int v;
+  if (TYPE_UNSIGNED (type))
+    v = cst.zext (TYPE_PRECISION (type));
+  else
+    v = cst.sext (TYPE_PRECISION (type));
+
+  return build_int_cst_wide (type, v.elt (0), v.elt (1));

this needs an assert that the wide-int contains two HWIs.

+#ifndef GENERATOR_FILE
+extern tree wide_int_to_tree (tree type, const wide_int &cst);
+#endif

why's that?  The header inclusion isn't guarded that way.

Stopping here, skipping to wide-int.[ch]

+#define DEBUG_WIDE_INT
+#ifdef DEBUG_WIDE_INT
+  /* Debugging routines.  */
+  static void debug_vw  (const char* name, int r, const wide_int& o0);
+  static void debug_vwh (const char* name, int r, const wide_int &o0,
+                        HOST_WIDE_INT o1);

there is DEBUG_FUNCTION.

+/* This is the maximal size of the buffer needed for dump.  */
+const int MAX = (MAX_BITSIZE_MODE_ANY_INT / 4
+                + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);

I'd prefer a target macro for this, not anything based off
MAX_BITSIZE_MODE_ANY_INT just to allow no-op transition of a
target to wide-ints (which IMHO should be the default for all targets,
simplifying the patch).

+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode
mode, bool *overflow)
+{
...
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+              "wide_int::from_uhwi", result.dump (buf0), op0);
+    }
+#endif

hm, ok ... I suppose the debug stuff (which looks very noisy) is going to be
removed before this gets committed anywhere?

+wide_int
+wide_int::from_int_cst (const_tree tcst)
+{
+#if 1
+  wide_int result;
+  tree type = TREE_TYPE (tcst);

should just call wide_it::from_double_int (tree_to_double_int (tcst))

As I said elsewhere I don't think only allowing precisions that are somewhere
in any mode is good enough.  We need the actual precision here (everywhere).

Index: gcc/wide-int.h
===================================================================
--- gcc/wide-int.h      (revision 0)
+++ gcc/wide-int.h      (revision 0)
@@ -0,0 +1,718 @@
+/* Operations with very long integers.
+   Copyright (C) 2012 Free Software Foundation, Inc.
...
+
+#ifndef GENERATOR_FILE
+#include "hwint.h"
+#include "options.h"
+#include "tm.h"
+#include "insn-modes.h"
+#include "machmode.h"
+#include "double-int.h"
+#include <gmp.h>
+#include "insn-modes.h"

ugh.  Compare this with double-int.h which just needs <gmp.h> (and even that
is a red herring) ...

+#define wide_int_minus_one(MODE) (wide_int::from_shwi (-1, MODE))
+#define wide_int_zero(MODE)      (wide_int::from_shwi (0, MODE))
+#define wide_int_one(MODE)       (wide_int::from_shwi (1, MODE))
+#define wide_int_two(MODE)       (wide_int::from_shwi (2, MODE))
+#define wide_int_ten(MODE)       (wide_int::from_shwi (10, MODE))

add static functions like

  wide_int wide_int::zero (MODE)

+class wide_int {
+  /* Internal representation.  */
+  HOST_WIDE_INT val[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  unsigned short len;
+  enum machine_mode mode;

you really need to store the precision here, not the mode.  We do not have
a distinct mode for each of the tree constant precisions we see.  So what
might work for RTL will later fail on trees, so better do it correct
from the start
(overloads using mode rather than precision may be acceptable - similarly
I'd consider overloads for tree types).

len seems redundant unless you want to optimize encoding.
len == (precision + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT.

+  enum Op {
+    NONE,

we don't have sth like this in double-int.h, why was the double-int mechanism
not viable?

+  static wide_int from_int_cst (const_tree);
+  static wide_int from_rtx (const_rtx, enum machine_mode);

from_tree instead of from_int_cst?  I miss from_pair.

+  HOST_WIDE_INT to_shwi (int prec) const;

isn't the precision encoded?  If it's a different precision this seems to
combine two primitives - is that really that convenient (if so that hints
at some oddity IMHO).

+  static wide_int max_value (const enum machine_mode mode, Op sgn);
+  static wide_int max_value (const enum machine_mode mode, int prec, Op sgn);
+  static wide_int min_value (const enum machine_mode mode, Op sgn);
+  static wide_int min_value (const enum machine_mode mode, int prec, Op sgn);

again prec seems redundant to me.  double-int uses 'bool uns', why is this
different here?  What happens for NONE, TRUNC?

+  inline unsigned short get_len () const;
+  inline void set_len (unsigned int);

the length should be an implementation detail, no?  Important is only
the precision of the number.  So this shouldn' t be exported at least.

+  inline int full_len () const;

what's this?

+  inline enum machine_mode get_mode () const;
+  inline void set_mode (enum machine_mode m);

not sure if we want machine-mode/precision mutating operations (similar
to length mutating operations).  I guess better not.

+  wide_int copy (enum machine_mode mode) const;

why does this need a mode argument?  Maybe 'copy' isn't a good name?

+  static inline HOST_WIDE_INT sext (HOST_WIDE_INT src, int prec);
+  static inline HOST_WIDE_INT zext (HOST_WIDE_INT src, int prec);

doesn't belong to wide_int::

+#define wide_int_smin(OP0,OP1)  ((OP0).lts_p (OP1) ? (OP0) : (OP1))
+#define wide_int_smax(OP0,OP1)  ((OP0).lts_p (OP1) ? (OP1) : (OP0))
+#define wide_int_umin(OP0,OP1)  ((OP0).ltu_p (OP1) ? (OP0) : (OP1))
+#define wide_int_umax(OP0,OP1)  ((OP0).ltu_p (OP1) ? (OP1) : (OP0))

use inline functions

+void
+wide_int::set_len (unsigned int l)
+{
+  gcc_assert (l < MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT);

use gcc_checking_assert everywhere.


Overall it's not too bad.  The mode vs. precision thing needs to be sorted
out and I'd like TARGET_SUPPORTS_WIDE_INT not be introduced,
even transitional.  Just make it possible to have the default be the
existing size of CONST_DOUBLE.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 13:18                           ` Richard Sandiford
@ 2012-10-05 13:53                             ` Richard Guenther
  2012-10-05 14:15                               ` Richard Sandiford
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Guenther @ 2012-10-05 13:53 UTC (permalink / raw)
  To: Richard Guenther, Kenneth Zadeck, Mike Stump, gcc-patches, rdsandiford

On Fri, Oct 5, 2012 at 3:18 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Sandiford <rdsandiford@googlemail.com> writes:
>>>>> How is CONST_WIDE_INT variable size?
>>>>
>>>> It's just the usual trailing variable-length array thing.
>>>
>>> Good.  Do you get rid of CONST_DOUBLE (for integers) at the same time?
>>
>> Yeah.  I initially thought it might be OK to keep them and have
>> CONST_INT, integer CONST_DOUBLEs and CONST_WIDE_INT alongside
>> each other.  (The way the patch is structured means that the
>> choice of whether to keep integer CONST_DOUBLEs can be changed
>> very easily.)  But Kenny convinced me it was a bad idea.
>
> Sorry to follow up on myself, but to clarify: I was talking about
> converted targets here.  (As in, I originally thought even converted
> targets could continue to use integer CONST_DOUBLEs.)
>
> Unconverted targets continue to use CONST_DOUBLE.

Why is it that not all targets are "converted"?  What's the difficulty
with that?
I really do not like partially transitioning there.

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 13:53                             ` Richard Guenther
@ 2012-10-05 14:15                               ` Richard Sandiford
  2012-10-05 14:36                                 ` Richard Guenther
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2012-10-05 14:15 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Kenneth Zadeck, Mike Stump, gcc-patches

Richard Guenther <richard.guenther@gmail.com> writes:
> On Fri, Oct 5, 2012 at 3:18 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Sandiford <rdsandiford@googlemail.com> writes:
>>>>>> How is CONST_WIDE_INT variable size?
>>>>>
>>>>> It's just the usual trailing variable-length array thing.
>>>>
>>>> Good.  Do you get rid of CONST_DOUBLE (for integers) at the same time?
>>>
>>> Yeah.  I initially thought it might be OK to keep them and have
>>> CONST_INT, integer CONST_DOUBLEs and CONST_WIDE_INT alongside
>>> each other.  (The way the patch is structured means that the
>>> choice of whether to keep integer CONST_DOUBLEs can be changed
>>> very easily.)  But Kenny convinced me it was a bad idea.
>>
>> Sorry to follow up on myself, but to clarify: I was talking about
>> converted targets here.  (As in, I originally thought even converted
>> targets could continue to use integer CONST_DOUBLEs.)
>>
>> Unconverted targets continue to use CONST_DOUBLE.
>
> Why is it that not all targets are "converted"?  What's the difficulty
> with that?
> I really do not like partially transitioning there.

The problem is that CONST_DOUBLE as it exists today has two meanings:
a floating-point meaning and an integer meaning.  Ports that handle
CONST_DOUBLEs are aware of this and expect the two things to have
the same rtx code.  Whereas in a converted port, the two things
have different rtx codes, and the integers have a different
representation from the current low/high pair.

So to take the first hit in config/alpha/alpha.c,
namely alpha_rtx_costs:

    case CONST_DOUBLE:
      if (x == CONST0_RTX (mode))
	*total = 0;
      else if ((outer_code == PLUS && add_operand (x, VOIDmode))
	       || (outer_code == AND && and_operand (x, VOIDmode)))
	*total = 0;
      else if (add_operand (x, VOIDmode) || and_operand (x, VOIDmode))
	*total = 2;
      else
	*total = COSTS_N_INSNS (2);
      return true;

What could the patch do to make this work without modification?
The middle two cases are for integers, but the first and last
presumably apply to both integers and floats.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 14:15                               ` Richard Sandiford
@ 2012-10-05 14:36                                 ` Richard Guenther
  2012-10-05 14:41                                   ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Guenther @ 2012-10-05 14:36 UTC (permalink / raw)
  To: Richard Guenther, Kenneth Zadeck, Mike Stump, gcc-patches, rdsandiford

On Fri, Oct 5, 2012 at 4:14 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Guenther <richard.guenther@gmail.com> writes:
>> On Fri, Oct 5, 2012 at 3:18 PM, Richard Sandiford
>> <rdsandiford@googlemail.com> wrote:
>>> Richard Sandiford <rdsandiford@googlemail.com> writes:
>>>>>>> How is CONST_WIDE_INT variable size?
>>>>>>
>>>>>> It's just the usual trailing variable-length array thing.
>>>>>
>>>>> Good.  Do you get rid of CONST_DOUBLE (for integers) at the same time?
>>>>
>>>> Yeah.  I initially thought it might be OK to keep them and have
>>>> CONST_INT, integer CONST_DOUBLEs and CONST_WIDE_INT alongside
>>>> each other.  (The way the patch is structured means that the
>>>> choice of whether to keep integer CONST_DOUBLEs can be changed
>>>> very easily.)  But Kenny convinced me it was a bad idea.
>>>
>>> Sorry to follow up on myself, but to clarify: I was talking about
>>> converted targets here.  (As in, I originally thought even converted
>>> targets could continue to use integer CONST_DOUBLEs.)
>>>
>>> Unconverted targets continue to use CONST_DOUBLE.
>>
>> Why is it that not all targets are "converted"?  What's the difficulty
>> with that?
>> I really do not like partially transitioning there.
>
> The problem is that CONST_DOUBLE as it exists today has two meanings:
> a floating-point meaning and an integer meaning.  Ports that handle
> CONST_DOUBLEs are aware of this and expect the two things to have
> the same rtx code.  Whereas in a converted port, the two things
> have different rtx codes, and the integers have a different
> representation from the current low/high pair.
>
> So to take the first hit in config/alpha/alpha.c,
> namely alpha_rtx_costs:
>
>     case CONST_DOUBLE:
>       if (x == CONST0_RTX (mode))
>         *total = 0;
>       else if ((outer_code == PLUS && add_operand (x, VOIDmode))
>                || (outer_code == AND && and_operand (x, VOIDmode)))
>         *total = 0;
>       else if (add_operand (x, VOIDmode) || and_operand (x, VOIDmode))
>         *total = 2;
>       else
>         *total = COSTS_N_INSNS (2);
>       return true;
>
> What could the patch do to make this work without modification?
> The middle two cases are for integers, but the first and last
> presumably apply to both integers and floats.

I didn't say it does not require changes, just that the transition should be
finished.  Some ports have little CONST_DOUBLE uses (which is what
I am grepping for), and if the max-wide-int-size matches that of the
current CONST_DOUBLE there is little chance for code generation
differences (in fact there should be none, correct?).

In the current patch no target is converted (maybe that's just going to
be 5/n?), I'd like to see at least one commonly tested target converted
and if we don't convert all targets another commonly tested target
to stay unconverted (just check gcc-testresults for which pair of targets
that would work).  Definitely at the end of stage3 we should have zero
unconverted targets (but I doubt converting them is a huge task - I have
converted the VECTOR_CST representation as well and we've had
the location + BLOCK merge and other changes affecting all targets).

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 14:36                                 ` Richard Guenther
@ 2012-10-05 14:41                                   ` Kenneth Zadeck
  2012-10-05 14:53                                     ` Richard Sandiford
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-05 14:41 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Mike Stump, gcc-patches, rdsandiford


On 10/05/2012 10:36 AM, Richard Guenther wrote:
> On Fri, Oct 5, 2012 at 4:14 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Guenther <richard.guenther@gmail.com> writes:
>>> On Fri, Oct 5, 2012 at 3:18 PM, Richard Sandiford
>>> <rdsandiford@googlemail.com> wrote:
>>>> Richard Sandiford <rdsandiford@googlemail.com> writes:
>>>>>>>> How is CONST_WIDE_INT variable size?
>>>>>>> It's just the usual trailing variable-length array thing.
>>>>>> Good.  Do you get rid of CONST_DOUBLE (for integers) at the same time?
>>>>> Yeah.  I initially thought it might be OK to keep them and have
>>>>> CONST_INT, integer CONST_DOUBLEs and CONST_WIDE_INT alongside
>>>>> each other.  (The way the patch is structured means that the
>>>>> choice of whether to keep integer CONST_DOUBLEs can be changed
>>>>> very easily.)  But Kenny convinced me it was a bad idea.
>>>> Sorry to follow up on myself, but to clarify: I was talking about
>>>> converted targets here.  (As in, I originally thought even converted
>>>> targets could continue to use integer CONST_DOUBLEs.)
>>>>
>>>> Unconverted targets continue to use CONST_DOUBLE.
>>> Why is it that not all targets are "converted"?  What's the difficulty
>>> with that?
>>> I really do not like partially transitioning there.
>> The problem is that CONST_DOUBLE as it exists today has two meanings:
>> a floating-point meaning and an integer meaning.  Ports that handle
>> CONST_DOUBLEs are aware of this and expect the two things to have
>> the same rtx code.  Whereas in a converted port, the two things
>> have different rtx codes, and the integers have a different
>> representation from the current low/high pair.
>>
>> So to take the first hit in config/alpha/alpha.c,
>> namely alpha_rtx_costs:
>>
>>      case CONST_DOUBLE:
>>        if (x == CONST0_RTX (mode))
>>          *total = 0;
>>        else if ((outer_code == PLUS && add_operand (x, VOIDmode))
>>                 || (outer_code == AND && and_operand (x, VOIDmode)))
>>          *total = 0;
>>        else if (add_operand (x, VOIDmode) || and_operand (x, VOIDmode))
>>          *total = 2;
>>        else
>>          *total = COSTS_N_INSNS (2);
>>        return true;
>>
>> What could the patch do to make this work without modification?
>> The middle two cases are for integers, but the first and last
>> presumably apply to both integers and floats.
> I didn't say it does not require changes, just that the transition should be
> finished.  Some ports have little CONST_DOUBLE uses (which is what
> I am grepping for), and if the max-wide-int-size matches that of the
> current CONST_DOUBLE there is little chance for code generation
> differences (in fact there should be none, correct?).
>
> In the current patch no target is converted (maybe that's just going to
> be 5/n?), I'd like to see at least one commonly tested target converted
> and if we don't convert all targets another commonly tested target
> to stay unconverted (just check gcc-testresults for which pair of targets
> that would work).  Definitely at the end of stage3 we should have zero
> unconverted targets (but I doubt converting them is a huge task - I have
> converted the VECTOR_CST representation as well and we've had
> the location + BLOCK merge and other changes affecting all targets).
>
> Richard.
i will convert ppc if that is what it takes.   david's office is 4 isles 
away and mike has a lot of experience on ppc also.  (this is unless 
richard is willing to do mips one afternoon.)   I have done my two 
private ports but i understand that that should not count.
>> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 14:41                                   ` Kenneth Zadeck
@ 2012-10-05 14:53                                     ` Richard Sandiford
  0 siblings, 0 replies; 217+ messages in thread
From: Richard Sandiford @ 2012-10-05 14:53 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Richard Guenther, Mike Stump, gcc-patches

Kenneth Zadeck <zadeck@naturalbridge.com> writes:
> i will convert ppc if that is what it takes.   david's office is 4 isles 
> away and mike has a lot of experience on ppc also.  (this is unless 
> richard is willing to do mips one afternoon.)

'Fraid MIPS is very boring as far as this is concerned.  MIPS sets
need_64bit_hwint to yes and has no 128-bit registers, so CONST_DOUBLE
is already restricted to floating-point values.

It might be interesting to see what happens without need_64bit_hwint,
but only once double_int has been removed.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 13:49                         ` Richard Guenther
@ 2012-10-05 16:34                           ` Kenneth Zadeck
  2012-10-05 17:29                             ` Richard Sandiford
  2012-10-07 12:47                             ` patch to fix constant math Richard Guenther
  0 siblings, 2 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-05 16:34 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Mike Stump, gcc-patches, rdsandiford

richard s,
there are two comments that i deferred to you.   that have the word 
richard in them,

richi,
thank, i will start doing this now.

kenny
On 10/05/2012 09:49 AM, Richard Guenther wrote:
> On Fri, Oct 5, 2012 at 2:39 PM, Richard Guenther
> <richard.guenther@gmail.com> wrote:
>> Ok, I see where you are going.  Let me look at the patch again.
> * The introduction and use of CONST_SCALAR_INT_P could be split out
>    (obvious and good)
>
> * DEF_RTL_EXPR(CONST_WIDE_INT, "const_wide_int", "", RTX_CONST_OBJ)
>    defining that new RTX is orthogonal to providing the wide_int abstraction
>    for operating on CONST_INT and CONST_DOUBLE, right?
>
> @@ -144,6 +144,7 @@ static bool
>   prefer_and_bit_test (enum machine_mode mode, int bitnum)
>   {
>     bool speed_p;
> +  wide_int mask = wide_int::set_bit_in_zero (bitnum, mode);
>
> set_bit_in_zero ... why use this instead of
> wide_int::zero (mode).set_bit (bitnum) that would match the old
> double_int_zero.set_bit interface and be more composed of primitives?
adding something like this was just based on usage.    We do this 
operation all over the place, why not make it concise and efficient.     
The api is very bottom up.   I looked at what the clients were doing all 
over the place and added those functions.

wide-int has both and_not and or_not.   double-int only has and_not, but 
there are a lot of places in where you do or_nots, so we have or_not also.

>     if (and_test == 0)
>       {
> @@ -164,8 +165,7 @@ prefer_and_bit_test (enum machine_mode m
>       }
>
>     /* Fill in the integers.  */
> -  XEXP (and_test, 1)
> -    = immed_double_int_const (double_int_zero.set_bit (bitnum), mode);
> +  XEXP (and_test, 1) = immed_wide_int_const (mask);
>
> I suppose immed_wide_int_const may create a CONST_INT, a CONST_DOUBLE
> or a CONST_WIDE_INT?
yes, on converted targets it builds const_ints and const_wide_ints and 
on unconverted targets it builds const_ints and const_doubles.    The 
reason i did not want to convert the targets is that the code that lives 
in the targets generally wants to use the values to create constants and 
this code is very very very target specific.
>
> +#if TARGET_SUPPORTS_WIDE_INT
> +/* Returns 1 if OP is an operand that is a CONST_INT or CONST_WIDE_INT.  */
> +int
> +const_scalar_int_operand (rtx op, enum machine_mode mode)
> +{
>
> why is it necessary to condition anything on TARGET_SUPPORTS_WIDE_INT?
> It seems testing/compile coverage of this code will be bad ...
>
> Can't you simply map CONST_WIDE_INT to CONST_DOUBLE for targets
The accessors for the two are completely different.    const doubles 
"know" that there are exactly two hwi's.   for const_wide_ints, you only 
know that the len is greater than 1.   anything with len 1 would be 
CONST_INT.

In a modern c++ world, const_int would be a subtype of const_int, but 
that is a huge patch.

> not supporting CONST_WIDE_INT (what does it mean to "support"
> CONST_WIDE_INT?  Does a target that supports CONST_WIDE_INT no
> longer use CONST_DOUBLEs for integers?)
yes, that is exactly what it means.
> +  if (!CONST_WIDE_INT_P (op))
> +    return 0;
>
> hm, that doesn't match the comment (CONST_INT is supposed to return 1 as well).
> The comment doesn't really tell what the function does it seems,
I need some context here to reply.

> +      int prec = GET_MODE_PRECISION (mode);
> +      int bitsize = GET_MODE_BITSIZE (mode);
> +
> +      if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
> +       return 0;
>
> it's mode argument is not documented.  And this doesn't even try to see if
> the constant would fit the mode anyway (like if it's zero).  Not sure what
> the function is for.
I will upgrade the comments, they were inherited from the old version 
with the const_double changed to the const_wide_int

> +       {
> +         /* Multiword partial int.  */
> +         HOST_WIDE_INT x
> +           = CONST_WIDE_INT_ELT (op, CONST_WIDE_INT_NUNITS (op) - 1);
> +         return (wide_int::sext (x, prec & (HOST_BITS_PER_WIDE_INT - 1))
> +                 == x);
>
> err - so now we have wide_int with a mode but we pass in another mode
> and see if they have the same value?  Same value as-in signed value?
> Which probably is why you need to rule out different size constants above?
> Because you don't know whether to sign or zero extend?
no it is worse than that.   I made the decision, which i think is 
correct, that we were not going to carry the mode inside 
const_wide_int.   The justification was that we do not do it for 
const_int.    There is a comment in the constructor for const_wide_int 
that says it would be so easy to just put this in.

But, this is an old api that did not change.   only the internals 
changed to support const_wide_int.

>
> +/* Returns 1 if OP is an operand that is a CONST_WIDE_INT.  */
> +int
> +const_wide_int_operand (rtx op, enum machine_mode mode)
> +{
>
> similar comments, common code should be factored out at least.
> Instead of conditioning a whole set of new function on supports-wide-int
> please add cases to the existing functions to avoid diverging in pieces
> that both kind of targets support.
in some places i do one and in some i do the other.   it really just 
depends on how much common code there was.   For these there was almost 
no common code.

> @@ -2599,7 +2678,7 @@ constrain_operands (int strict)
>                  break;
>
>                case 'n':
> -               if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
> +               if (CONST_SCALAR_INT_P (op))
>                    win = 1;
>
> factoring out this changes would really make the patch less noisy.
i will this weekend.
> skipping to rtl.h bits
>
> +struct GTY((variable_size)) hwivec_def {
> +  int num_elem;                /* number of elements */
> +  HOST_WIDE_INT elem[1];
> +};
>
> num_elem seems redundant and computable from GET_MODE_SIZE.
NOT AT ALL.   CONST_WIDE_INT and TREE_INT_CST only have enough elements 
in the array to hold the actual value, they do not have enough elements 
to hold the mode or type.
in real life almost all integer constants of any type are very small.    
in the rtl word, we almost never actually create any CONST_WIDE_INT 
outside of the test cases, because CONST_INT handles the cases, and i 
assume that at the tree level, almost every int cst will have an len of 1.


> Or do you want to optimize encoding like for CONST_INT (and unlike
> CONST_DOUBLE)?  I doubt the above packs nicely into rtx_def?
> A general issue of it though - we waste 32bits on 64bit hosts in
> rtx_def between the bits and the union.  Perfect place for num_elem
> (if you really need it) and avoids another 4 byte hole.  Similar issue
> exists in rtvec_def.
I am going to let richard answer this.

> back to where I was
>
> @@ -645,6 +673,10 @@ iterative_hash_rtx (const_rtx x, hashval
>         return iterative_hash_object (i, hash);
>       case CONST_INT:
>         return iterative_hash_object (INTVAL (x), hash);
> +    case CONST_WIDE_INT:
> +      for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
> +       hash = iterative_hash_object (CONST_WIDE_INT_ELT (x, i), hash);
> +      return hash;
>
> I see CONST_DOUBLEs value is not hashed.  Why hash wide-ints value?
There are a lot of ugly things that one uncovers when one looks at code 
this old.
the idea was to bring whatever i touched up to best practice standards.

> Seeing
>
> +#define HWI_GET_NUM_ELEM(HWIVEC)       ((HWIVEC)->num_elem)
> +#define HWI_PUT_NUM_ELEM(HWIVEC, NUM)  ((HWIVEC)->num_elem = (NUM))
>
> skipping to
>
> +#if TARGET_SUPPORTS_WIDE_INT
> +  {
> +    rtx value = const_wide_int_alloc (len);
> +    unsigned int i;
> +
> +    /* It is so tempting to just put the mode in here.  Must control
> +       myself ... */
> +    PUT_MODE (value, VOIDmode);
> +    HWI_PUT_NUM_ELEM (CONST_WIDE_INT_VEC (value), len);
>
> why is NUM_ELEM not set in const_wide_int_alloc, and only there?
>
> +extern rtx rtx_alloc_stat_v (RTX_CODE MEM_STAT_DECL, int);
> +#define rtx_alloc_v(c, SZ) rtx_alloc_stat_v (c MEM_STAT_INFO, SZ)
> +#define const_wide_int_alloc(NWORDS)                           \
> +  rtx_alloc_v (CONST_WIDE_INT,                                 \
> +              (sizeof (struct hwivec_def)                      \
> +               + ((NWORDS)-1) * sizeof (HOST_WIDE_INT)))       \
>
> because it's a macro(?).  Ugh.
>
> I see CONST_DOUBLE for ints and CONST_WIDE_INT for ints use
> is mutually exclusive.  Good.  What's the issue with converting targets?
> Just retain the existing 2 * HWI limit by default.
I have answered this elsewhere, the constant generation code on some 
platforms is tricky and i felt that would require knowledge of the port 
that i did not have.   it is not just a bunch of c code, it is also 
changing patterns in the md files.

> +#if TARGET_SUPPORTS_WIDE_INT
> +
> +/* Match CONST_*s that can represent compile-time constant integers.  */
> +#define CASE_CONST_SCALAR_INT \
> +   case CONST_INT: \
> +   case CONST_WIDE_INT
> +
>
> I regard this abstraction is mostly because the transition is not finished.
> Not sure if seeing CASE_CONST_SCALAR_INT, CASE_CONST_UNIQUE (?),
> CASE_CONST_ANY adds more to the confusion than spelling out all of them.
> Isn't there sth like a tree-code-class for RTXen?  That would catch
> CASE_CONST_ANY, no?
however, those abstractions are already in the trunk.   They were put in 
earlier to make this patch smaller.
> @@ -3081,6 +3081,8 @@ commutative_operand_precedence (rtx op)
>     /* Constants always come the second operand.  Prefer "nice" constants.  */
>     if (code == CONST_INT)
>       return -8;
> +  if (code == CONST_WIDE_INT)
> +    return -8;
>     if (code == CONST_DOUBLE)
>       return -7;
>     if (code == CONST_FIXED)
>
> I think it should be the same as CONST_DOUBLE which it "replaces".
> Likewise below, that avoids code generation changes (which there should
> be none for a target that is converted, right?).
not clear because it does not really replace const double - remember 
that const double still holds fp stuff.    another one for richard to 
comment on.
> @@ -5351,6 +5355,20 @@ split_double (rtx value, rtx *first, rtx
>              }
>          }
>       }
> +  else if (GET_CODE (value) == CONST_WIDE_INT)
> +    {
> +      gcc_assert (CONST_WIDE_INT_NUNITS (value) == 2);
> +      if (WORDS_BIG_ENDIAN)
> +       {
> +         *first = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
> +         *second = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
> +       }
> +      else
> +       {
> +         *first = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
> +         *second = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
> +       }
> +    }
>
> scary ;)
unbelievably scary.    This is one of those places where i really do not 
know what the code is doing and so i just put in something that was 
minimally correct.    when we get some code where the assert hits then i 
will figure it out.

> Index: gcc/sched-vis.c
> ===================================================================
> --- gcc/sched-vis.c     (revision 191978)
> +++ gcc/sched-vis.c     (working copy)
> @@ -444,14 +444,31 @@ print_value (char *buf, const_rtx x, int
> ...
>       case CONST_DOUBLE:
> -      if (FLOAT_MODE_P (GET_MODE (x)))
> -       real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1);
> -      else
> +     if (TARGET_SUPPORTS_WIDE_INT == 0 && !FLOAT_MODE_P (GET_MODE (x)))
>          sprintf (t,
>                   "<" HOST_WIDE_INT_PRINT_HEX "," HOST_WIDE_INT_PRINT_HEX ">",
>                   (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x),
>                   (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x));
> +      else
> +       real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1);
>         cur = safe_concat (buf, cur, t);
>         break;
>
> I don't see that this hunk is needed?  In fact it's more confusing this way.
you are likely right.   this is really there to say that this code would 
go away if
(when) all targets support wide int,  but i will get rid of it.
> +/* If the target supports integers that are wider than two
> +   HOST_WIDE_INTs on the host compiler, then the target should define
> +   TARGET_SUPPORTS_WIDE_INT and make the appropriate fixups.
> +   Otherwise the compiler really is not robust.  */
> +#ifndef TARGET_SUPPORTS_WIDE_INT
> +#define TARGET_SUPPORTS_WIDE_INT 0
> +#endif
>
> I wonder what are the appropriate fixups?
it was in the mail of the original patch.    i will in the next round, 
transfer a cleaned up version of that into the doc for this target hook.
>
> -/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
> -   GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
> +/* Return a CONST_INT, CONST_WIDE_INT, or CONST_DOUBLE corresponding
> +   to target reading GET_MODE_BITSIZE (MODE) bits from string constant
> +   STR.  */
>
> maybe being less specific in this kind of comments and just refering to
> RTX integer constants would be better?
will do, i have done some like that.
> ... skip ...
>
> Index: gcc/hwint.c
> ===================================================================
> --- gcc/hwint.c (revision 191978)
> +++ gcc/hwint.c (working copy)
> @@ -112,6 +112,29 @@ ffs_hwi (unsigned HOST_WIDE_INT x)
>   int
>   popcount_hwi (unsigned HOST_WIDE_INT x)
>   {
> +  /* Compute the popcount of a HWI using the algorithm from
> +     Hacker's Delight.  */
> +#if HOST_BITS_PER_WIDE_INT == 32
>
> separate patch please.  With a rationale.
fine.
> ...
>
> +/* Constructs tree in type TYPE from with value given by CST.  Signedness
> +   of CST is assumed to be the same as the signedness of TYPE.  */
> +
> +tree
> +wide_int_to_tree (tree type, const wide_int &cst)
> +{
> +  wide_int v;
> +  if (TYPE_UNSIGNED (type))
> +    v = cst.zext (TYPE_PRECISION (type));
> +  else
> +    v = cst.sext (TYPE_PRECISION (type));
> +
> +  return build_int_cst_wide (type, v.elt (0), v.elt (1));
>
> this needs an assert that the wide-int contains two HWIs.
as i said in an earlier mail, this is just transition code for when the 
tree level code goes in.
but i see your point and will add the assert.


> +#ifndef GENERATOR_FILE
> +extern tree wide_int_to_tree (tree type, const wide_int &cst);
> +#endif
>
> why's that?  The header inclusion isn't guarded that way.
there was a problem building without it.   but i will look into it.
> Stopping here, skipping to wide-int.[ch]
>
> +#define DEBUG_WIDE_INT
> +#ifdef DEBUG_WIDE_INT
> +  /* Debugging routines.  */
> +  static void debug_vw  (const char* name, int r, const wide_int& o0);
> +  static void debug_vwh (const char* name, int r, const wide_int &o0,
> +                        HOST_WIDE_INT o1);
>
> there is DEBUG_FUNCTION.
>
> +/* This is the maximal size of the buffer needed for dump.  */
> +const int MAX = (MAX_BITSIZE_MODE_ANY_INT / 4
> +                + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
>
> I'd prefer a target macro for this, not anything based off
> MAX_BITSIZE_MODE_ANY_INT just to allow no-op transition of a
> target to wide-ints (which IMHO should be the default for all targets,
> simplifying the patch).
>
> +wide_int
> +wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode
> mode, bool *overflow)
> +{
> ...
> +#ifdef DEBUG_WIDE_INT
> +  if (dump_file)
> +    {
> +      char buf0[MAX];
> +      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
> +              "wide_int::from_uhwi", result.dump (buf0), op0);
> +    }
> +#endif
>
> hm, ok ... I suppose the debug stuff (which looks very noisy) is going to be
> removed before this gets committed anywhere?
it is very noisy and i was just planning to turn it off.    but it is 
very useful when there is a problem so i was not planning to actually 
remove it immediately.

>
> +wide_int
> +wide_int::from_int_cst (const_tree tcst)
> +{
> +#if 1
> +  wide_int result;
> +  tree type = TREE_TYPE (tcst);
>
> should just call wide_it::from_double_int (tree_to_double_int (tcst))
>
> As I said elsewhere I don't think only allowing precisions that are somewhere
> in any mode is good enough.  We need the actual precision here (everywhere).
i think that the case has been made that what wide int needs to store 
inside it is the precision and bitsize and that passing in the mode/tree 
type is just a convenience.     I will make this change. Then we can 
have exposed constructors that just take bitsize and precision.


> Index: gcc/wide-int.h
> ===================================================================
> --- gcc/wide-int.h      (revision 0)
> +++ gcc/wide-int.h      (revision 0)
> @@ -0,0 +1,718 @@
> +/* Operations with very long integers.
> +   Copyright (C) 2012 Free Software Foundation, Inc.
> ...
> +
> +#ifndef GENERATOR_FILE
> +#include "hwint.h"
> +#include "options.h"
> +#include "tm.h"
> +#include "insn-modes.h"
> +#include "machmode.h"
> +#include "double-int.h"
> +#include <gmp.h>
> +#include "insn-modes.h"
>
> ugh.  Compare this with double-int.h which just needs <gmp.h> (and even that
> is a red herring) ...
>
> +#define wide_int_minus_one(MODE) (wide_int::from_shwi (-1, MODE))
> +#define wide_int_zero(MODE)      (wide_int::from_shwi (0, MODE))
> +#define wide_int_one(MODE)       (wide_int::from_shwi (1, MODE))
> +#define wide_int_two(MODE)       (wide_int::from_shwi (2, MODE))
> +#define wide_int_ten(MODE)       (wide_int::from_shwi (10, MODE))
>
> add static functions like
>
>    wide_int wide_int::zero (MODE)
ok
> +class wide_int {
> +  /* Internal representation.  */
> +  HOST_WIDE_INT val[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
> +  unsigned short len;
> +  enum machine_mode mode;
>
> you really need to store the precision here, not the mode.  We do not have
> a distinct mode for each of the tree constant precisions we see.  So what
> might work for RTL will later fail on trees, so better do it correct
> from the start
> (overloads using mode rather than precision may be acceptable - similarly
> I'd consider overloads for tree types).
discussed above.
> len seems redundant unless you want to optimize encoding.
> len == (precision + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT.
that is exactly what we do.   However, we are optimizing time, not space.
the value is always stored in compressed form, i.e the same 
representation as is used inside the CONST_WIDE_INTs and INT_CSTs. this 
makes the transformation between them very fast.   And since we do this 
a lot, it needs to be fast.   So the len is the number of HWIs needed to 
represent the value which is typically less than what would be implied 
by the precision.
> +  enum Op {
> +    NONE,
>
> we don't have sth like this in double-int.h, why was the double-int mechanism
> not viable?
i have chosen to use enums for things rather than passing booleans.
> +  static wide_int from_int_cst (const_tree);
> +  static wide_int from_rtx (const_rtx, enum machine_mode);
>
> from_tree instead of from_int_cst?
ok
>    I miss from_pair.
why do you need this?
> +  HOST_WIDE_INT to_shwi (int prec) const;
>
> isn't the precision encoded?  If it's a different precision this seems to
> combine two primitives - is that really that convenient (if so that hints
> at some oddity IMHO).
this is an override of the one that does not take the precision. and it 
is that convenient.
I think that it is well understood that there are strange things in gcc.
> +  static wide_int max_value (const enum machine_mode mode, Op sgn);
> +  static wide_int max_value (const enum machine_mode mode, int prec, Op sgn);
> +  static wide_int min_value (const enum machine_mode mode, Op sgn);
> +  static wide_int min_value (const enum machine_mode mode, int prec, Op sgn);
again this is a style thing.    boolean parameters are more likely to 
get mangled.
> again prec seems redundant to me.  double-int uses 'bool uns', why is this
> different here?  What happens for NONE, TRUNC?
>
> +  inline unsigned short get_len () const;
> +  inline void set_len (unsigned int);
>
> the length should be an implementation detail, no?  Important is only
> the precision of the number.  So this shouldn' t be exported at least.
see above where you talk about len before.
> +  inline int full_len () const;
>
> what's this?
it is used by dwarf2out, it is a little redundant with precision.
dwarf2out is one of the places in the compiler that really has to know 
how many HWIs are used to represent the uncompressed number because that 
is what it is going to be dumping into the debug records.   it is used 
in 10 places there, all for pretty much the same reason.
> +  inline enum machine_mode get_mode () const;
> +  inline void set_mode (enum machine_mode m);
>
> not sure if we want machine-mode/precision mutating operations (similar
> to length mutating operations).  I guess better not.
This is one of the ugly worlds of abstractions.   the issue is that when 
you convert from/to something else into/from wide-int, then one of those 
two abstractions is going to have to reveal their innards.
That is the use of this.

> +  wide_int copy (enum machine_mode mode) const;
>
> why does this need a mode argument?  Maybe 'copy' isn't a good name?
perhaps, i guess at the tree level there are a lot of functions with the 
word "force" in their name.
however, here you always get a copy.
> +  static inline HOST_WIDE_INT sext (HOST_WIDE_INT src, int prec);
> +  static inline HOST_WIDE_INT zext (HOST_WIDE_INT src, int prec);
>
> doesn't belong to wide_int::
i will move them to hwint
> +#define wide_int_smin(OP0,OP1)  ((OP0).lts_p (OP1) ? (OP0) : (OP1))
> +#define wide_int_smax(OP0,OP1)  ((OP0).lts_p (OP1) ? (OP1) : (OP0))
> +#define wide_int_umin(OP0,OP1)  ((OP0).ltu_p (OP1) ? (OP0) : (OP1))
> +#define wide_int_umax(OP0,OP1)  ((OP0).ltu_p (OP1) ? (OP1) : (OP0))
>
> use inline functions
ok
> +void
> +wide_int::set_len (unsigned int l)
> +{
> +  gcc_assert (l < MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT);
>
> use gcc_checking_assert everywhere.
ok
>
> Overall it's not too bad.  The mode vs. precision thing needs to be sorted
as i said, i give in to this.
> out and I'd like TARGET_SUPPORTS_WIDE_INT not be introduced,
> even transitional.  Just make it possible to have the default be the
> existing size of CONST_DOUBLE.
i do not see how to do this.    we did what we could to minimize this, 
but at some point a target is going to have to indicate that it can 
behave in the new way, and in the new way thing work differently.

kenny
> Thanks,
> Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 16:34                           ` Kenneth Zadeck
@ 2012-10-05 17:29                             ` Richard Sandiford
  2012-10-05 17:53                               ` Kenneth Zadeck
  2012-10-05 22:12                               ` patch to fix constant math - first small patch Kenneth Zadeck
  2012-10-07 12:47                             ` patch to fix constant math Richard Guenther
  1 sibling, 2 replies; 217+ messages in thread
From: Richard Sandiford @ 2012-10-05 17:29 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Richard Guenther, Mike Stump, gcc-patches

Kenneth Zadeck <zadeck@naturalbridge.com> writes:
>> Or do you want to optimize encoding like for CONST_INT (and unlike
>> CONST_DOUBLE)?  I doubt the above packs nicely into rtx_def?
>> A general issue of it though - we waste 32bits on 64bit hosts in
>> rtx_def between the bits and the union.  Perfect place for num_elem
>> (if you really need it) and avoids another 4 byte hole.  Similar issue
>> exists in rtvec_def.
> I am going to let richard answer this.

I agree this would be nice, but (stating the obvious) only on targets
where there is a hole.  I suppose that translates to something like:

#if (HOST_BITS_PER_PTR > HOST_BITS_PER_INT \
     || HOST_BITS_PER_WIDE_INT > HOST_BITS_PER_INT)
#define RTL_LAYOUT 1
#else
#define RTL_LAYOUT 2
#endif

where HOST_BITS_PER_PTR would have to be set by a new configure-time test.
RTL_LAYOUT == 1 would put the CONST_WIDE_INT vector length in rtx_def itself,
probably as part of a new union, while RTL_LAYOUT == 2 would keep
it in its current place.

E.g. between:

  unsigned return_val : 1;

and:

  /* The first element of the operands of this rtx.
     The number of operands and their types are controlled
     by the `code' field, according to rtl.def.  */
  union u {

have:

#if RTL_LAYOUT == 1
  union {
    int num_elem;
  } u2;
#endif

And:

struct GTY((variable_size)) hwivec_def {
#if RTL_LAYOUT == 2
  int num_elem;
#endif
  HOST_WIDE_INT elem[1];
};

>> +#if TARGET_SUPPORTS_WIDE_INT
>> +
>> +/* Match CONST_*s that can represent compile-time constant integers.  */
>> +#define CASE_CONST_SCALAR_INT \
>> +   case CONST_INT: \
>> +   case CONST_WIDE_INT
>> +
>>
>> I regard this abstraction is mostly because the transition is not finished.
>> Not sure if seeing CASE_CONST_SCALAR_INT, CASE_CONST_UNIQUE (?),
>> CASE_CONST_ANY adds more to the confusion than spelling out all of them.
>> Isn't there sth like a tree-code-class for RTXen?  That would catch
>> CASE_CONST_ANY, no?

Not as things stand.  All constants are classified as RTX_CONST_OBJ,
which includes run-time constants like SYMBOL_REF as well.  Whether it
makes sense to change the classification is really a separate question
from this patch.  Besides, the other cases in the affected switch
statements aren't necessarily going to divide into classes either,
so we might still need CASE_CONST_ANY.

I'd like to keep these macros even after the conversion.  They make
it more obvious what property is being tested, instead of having various
subsets of the CONST_* codes included by name.  Reviewing the patch that
introduced the macros showed up instances where the existing switch
statements were wrong.

>> @@ -3081,6 +3081,8 @@ commutative_operand_precedence (rtx op)
>>     /* Constants always come the second operand.  Prefer "nice" constants.  */
>>     if (code == CONST_INT)
>>       return -8;
>> +  if (code == CONST_WIDE_INT)
>> +    return -8;
>>     if (code == CONST_DOUBLE)
>>       return -7;
>>     if (code == CONST_FIXED)
>>
>> I think it should be the same as CONST_DOUBLE which it "replaces".
>> Likewise below, that avoids code generation changes (which there should
>> be none for a target that is converted, right?).
> not clear because it does not really replace const double - remember 
> that const double still holds fp stuff.    another one for richard to 
> comment on.

I think it should be the same as CONST_INT.  Whether an integer
fits into a HWI or not shouldn't affect its precedence.

>> +/* This is the maximal size of the buffer needed for dump.  */
>> +const int MAX = (MAX_BITSIZE_MODE_ANY_INT / 4
>> +                + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
>>
>> I'd prefer a target macro for this, not anything based off
>> MAX_BITSIZE_MODE_ANY_INT just to allow no-op transition of a
>> target to wide-ints (which IMHO should be the default for all targets,
>> simplifying the patch).

Kenny didn't comment on this, but I disagree.  Part of the process of
"converting" a port is to ween it off any assumptions about the number
of HWIs.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 17:29                             ` Richard Sandiford
@ 2012-10-05 17:53                               ` Kenneth Zadeck
  2012-10-05 22:12                               ` patch to fix constant math - first small patch Kenneth Zadeck
  1 sibling, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-05 17:53 UTC (permalink / raw)
  To: Richard Guenther, Mike Stump, gcc-patches, rdsandiford


On 10/05/2012 01:29 PM, Richard Sandiford wrote:
>>> +/* This is the maximal size of the buffer needed for dump.  */
>>> >>+const int MAX = (MAX_BITSIZE_MODE_ANY_INT / 4
>>> >>+                + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
>>> >>
>>> >>I'd prefer a target macro for this, not anything based off
>>> >>MAX_BITSIZE_MODE_ANY_INT just to allow no-op transition of a
>>> >>target to wide-ints (which IMHO should be the default for all targets,
>>> >>simplifying the patch).
> Kenny didn't comment on this, but I disagree.  Part of the process of
> "converting" a port is to ween it off any assumptions about the number
> of HWIs.
i also disagree.    my patch is littered with are places like this.
consider:

@@ -5180,13 +4808,11 @@ static rtx
  simplify_immed_subreg (enum machine_mode outermode, rtx op,
                 enum machine_mode innermode, unsigned int byte)
  {
-  /* We support up to 512-bit values (for V8DFmode).  */
    enum {
-    max_bitsize = 512,
      value_bit = 8,
      value_mask = (1 << value_bit) - 1
    };
-  unsigned char value[max_bitsize / value_bit];
+  unsigned char value [MAX_BITSIZE_MODE_ANY_MODE/value_bit];
    int value_start;
    int i;
    int elem;

Would you want do have a target macro for this also?
The code works no matter what. we do not need to be chasing this kind of 
problem all over the place.

kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch
  2012-10-05 17:29                             ` Richard Sandiford
  2012-10-05 17:53                               ` Kenneth Zadeck
@ 2012-10-05 22:12                               ` Kenneth Zadeck
  2012-10-05 22:48                                 ` patch to fix constant math - second " Kenneth Zadeck
  2012-10-06  0:14                                 ` patch to fix constant math - first small patch Joseph S. Myers
  1 sibling, 2 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-05 22:12 UTC (permalink / raw)
  To: Richard Guenther, Mike Stump, gcc-patches, rdsandiford, Kenneth Zadeck

[-- Attachment #1: Type: text/plain, Size: 672 bytes --]

this patch adds two groups of things to hwint.h that are needed for 
wide-int.[ch].

A new data type, the HOST_HALF_WIDE_INT (and all of it related 
macros).   This type is defined to be exactly 1/2 the width of a 
HOST_WIDE_INT.  This is used by the multiplication and division routines 
in wide-int.c.   This is the type for the "digits" that are multiplied 
together or divided since you want to do the largest multiplication that 
you can do that yields a HOST_WIDE_INT as the result.

The zext_hwi and sext_hwi are simple convenience functions on HWIs.   
These were moved from the wide-int.h in the original patch at the 
request of richi.

ok for commit?

Kenny




[-- Attachment #2: p1-1.clog --]
[-- Type: text/plain, Size: 389 bytes --]

2012-10-5  Kenneth Zadeck <zadeck@naturalbridge.com>

	* hwint.h (HOST_BITS_PER_HALF_WIDE_INT, HOST_HALF_WIDE_INT,
	HOST_HALF_WIDE_INT_PRINT, HOST_HALF_WIDE_INT_PRINT_C,
	HOST_HALF_WIDE_INT_PRINT_DEC, HOST_HALF_WIDE_INT_PRINT_DEC_C,
	HOST_HALF_WIDE_INT_PRINT_UNSIGNED, HOST_HALF_WIDE_INT_PRINT_HEX,
	HOST_HALF_WIDE_INT_PRINT_HEX_PURE): New symbols.
	(sext_hwi, zext_hwi): New functions.
	

[-- Attachment #3: p1-1.diff --]
[-- Type: text/x-patch, Size: 4058 bytes --]

diff --git a/gcc/hwint.h b/gcc/hwint.h
index ca47148..07c4748 100644
--- a/gcc/hwint.h
+++ b/gcc/hwint.h
@@ -77,6 +77,40 @@ extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1];
 # endif
 #endif
 
+/* Print support for half a host wide int.  */
+#define HOST_BITS_PER_HALF_WIDE_INT (HOST_BITS_PER_WIDE_INT / 2)
+#if HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_LONG
+# define HOST_HALF_WIDE_INT long
+# define HOST_HALF_WIDE_INT_PRINT HOST_LONG_FORMAT
+# define HOST_HALF_WIDE_INT_PRINT_C "L"
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_INT
+# define HOST_HALF_WIDE_INT int
+# define HOST_HALF_WIDE_INT_PRINT ""
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_SHORT
+# define HOST_HALF_WIDE_INT short
+# define HOST_HALF_WIDE_INT_PRINT "h"
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#else
+#error Please add support for HOST_HALF_WIDE_INT
+#endif
+
+
 #define HOST_WIDE_INT_1 HOST_WIDE_INT_C(1)
 
 /* This is a magic identifier which allows GCC to figure out the type
@@ -94,9 +128,13 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
 # if HOST_BITS_PER_WIDE_INT == 64
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%016" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%016" HOST_LONG_FORMAT "x"
 # else
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%08" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%08" HOST_LONG_FORMAT "x"
 # endif
 #else
 # define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT
@@ -104,6 +142,8 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
   /* We can assume that 'long long' is at least 64 bits.  */
 # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
     "0x%" HOST_LONG_LONG_FORMAT "x%016" HOST_LONG_LONG_FORMAT "x"
+# define HOST_WIDE_INT_PRINT_PADDED_HEX \
+    "%016" HOST_LONG_LONG_FORMAT "x"
 #endif /* HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG */
 
 #define HOST_WIDE_INT_PRINT_DEC "%" HOST_WIDE_INT_PRINT "d"
@@ -277,4 +317,32 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT);
 
+/* Sign extend SRC starting from PREC.  */
+
+static inline HOST_WIDE_INT
+sext_hwi (HOST_WIDE_INT src, int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    {
+      int shift = HOST_BITS_PER_WIDE_INT - (prec & (HOST_BITS_PER_WIDE_INT - 1));
+      return (src << shift) >> shift;
+    }
+}
+
+/* Zero extend SRC starting from PREC.  */
+
+static inline HOST_WIDE_INT
+zext_hwi (HOST_WIDE_INT src, int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    return src & (((HOST_WIDE_INT)1
+		   << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
+}
+
+
+
 #endif /* ! GCC_HWINT_H */

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - second small patch
  2012-10-05 22:12                               ` patch to fix constant math - first small patch Kenneth Zadeck
@ 2012-10-05 22:48                                 ` Kenneth Zadeck
  2012-10-06 15:55                                   ` patch to fix constant math - third " Kenneth Zadeck
                                                     ` (2 more replies)
  2012-10-06  0:14                                 ` patch to fix constant math - first small patch Joseph S. Myers
  1 sibling, 3 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-05 22:48 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Richard Guenther, Mike Stump, gcc-patches, rdsandiford

[-- Attachment #1: Type: text/plain, Size: 400 bytes --]

This patch adds machinery to genmodes.c so that largest possible sizes 
of various data structures can be determined at gcc build time.  These 
functions create 3 symbols that are available in insn-modes.h:
MAX_BITSIZE_MODE_INT - the bitsize of the largest int.
MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int.
MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int.

[-- Attachment #2: p2-1.diff --]
[-- Type: text/x-patch, Size: 1539 bytes --]

Index: gcc/genmodes.c
===================================================================
--- gcc/genmodes.c	(revision 191978)
+++ gcc/genmodes.c	(working copy)
@@ -849,6 +849,38 @@ calc_wider_mode (void)
 
 #define print_closer() puts ("};")
 
+/* Compute the max bitsize of some of the classes of integers.  It may
+   be that there are needs for the other integer classes, and this
+   code is easy to extend.  */
+static void
+emit_max_int (void)
+{
+  unsigned int max, mmax;
+  struct mode_data *i;
+  int j;
+
+  puts ("");
+  for (max = 1, i = modes[MODE_INT]; i; i = i->next)
+    if (max < i->bytesize)
+	max = i->bytesize;
+  printf ("#define MAX_BITSIZE_MODE_INT %d*BITS_PER_UNIT\n", max);
+  mmax = max;
+  for (max = 1, i = modes[MODE_PARTIAL_INT]; i; i = i->next)
+    if (max < i->bytesize)
+	max = i->bytesize;
+  printf ("#define MAX_BITSIZE_MODE_PARTIAL_INT %d*BITS_PER_UNIT\n", max);
+  if (max > mmax)
+    mmax = max;
+  printf ("#define MAX_BITSIZE_MODE_ANY_INT %d*BITS_PER_UNIT\n", mmax);
+
+  mmax = 0;
+  for (j = 0; j < MAX_MODE_CLASS; j++)
+    for (i = modes[j]; i; i = i->next)
+      if (mmax < i->bytesize)
+	mmax = i->bytesize;
+  printf ("#define MAX_BITSIZE_MODE_ANY_MODE %d*BITS_PER_UNIT\n", mmax);
+}
+
 static void
 emit_insn_modes_h (void)
 {
@@ -913,6 +945,7 @@ enum machine_mode\n{");
 #endif
   printf ("#define CONST_MODE_IBIT%s\n", adj_ibit ? "" : " const");
   printf ("#define CONST_MODE_FBIT%s\n", adj_fbit ? "" : " const");
+  emit_max_int ();
   puts ("\
 \n\
 #endif /* insn-modes.h */");

[-- Attachment #3: p2-1.clog --]
[-- Type: text/plain, Size: 158 bytes --]

2012-10-5  Kenneth Zadeck <zadeck@naturalbridge.com>

   	* genmodes.c (emit_max_int): New function.
	(emit_insn_modes_h): Added call to emit_max_function.
	

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch
  2012-10-05 22:12                               ` patch to fix constant math - first small patch Kenneth Zadeck
  2012-10-05 22:48                                 ` patch to fix constant math - second " Kenneth Zadeck
@ 2012-10-06  0:14                                 ` Joseph S. Myers
  2012-10-08 19:25                                   ` Kenneth Zadeck
                                                     ` (2 more replies)
  1 sibling, 3 replies; 217+ messages in thread
From: Joseph S. Myers @ 2012-10-06  0:14 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Richard Guenther, Mike Stump, gcc-patches, rdsandiford

On Fri, 5 Oct 2012, Kenneth Zadeck wrote:

> +# define HOST_HALF_WIDE_INT_PRINT "h"

This may cause problems on hosts not supporting %hd (MinGW?), and there's 
no real need for using "h" here given the promotion of short to int; you 
can just use "" (rather than e.g. needing special handling in xm-mingw32.h 
like is done for HOST_LONG_LONG_FORMAT).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - third small patch
  2012-10-05 22:48                                 ` patch to fix constant math - second " Kenneth Zadeck
@ 2012-10-06 15:55                                   ` Kenneth Zadeck
  2012-10-08  9:08                                     ` Richard Guenther
  2012-10-08 11:37                                     ` Kenneth Zadeck
  2012-10-08  9:07                                   ` patch to fix constant math - second " Richard Guenther
  2013-02-27  0:28                                   ` patch to fix constant math - second small patch -patch ping for next stage 1 Kenneth Zadeck
  2 siblings, 2 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-06 15:55 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Richard Guenther, Mike Stump, gcc-patches, rdsandiford

This is the third patch in the series of patches to fix constant math.
this one changes some predicates at the rtl level to use the new 
predicate CONST_SCALAR_INT_P.
I did not include a few that were tightly intertwined with other changes.

Not all of these changes are strictly mechanical.   Richard, when 
reviewing this had me make additional changes to remove what he thought 
were latent bugs at the rtl level.   However, it appears that the bugs 
were not latent.    I do not know what is going on here but i am smart 
enough to not look a gift horse in the mouth.

All of this was done on the same machine with no changes and identical 
configs.  It is an x86-64 with ubuntu 12-4.

ok for commit?

in the logs below, gbBaseline is a trunk from friday and the gbWide is 
the same revision but with my patches.  Some of this like 
gfortran.dg/pr32627 is obviously flutter, but the rest does not appear 
to be.

=========
heracles:~/gcc(13) gccBaseline/contrib/compare_tests 
gbBaseline/gcc/testsuite/gcc/gcc.log gbWide/gcc/testsuite/gcc/gcc.log
New tests that PASS:

gcc.dg/builtins-85.c scan-assembler mysnprintf
gcc.dg/builtins-85.c scan-assembler-not __chk_fail
gcc.dg/builtins-85.c (test for excess errors)


heracles:~/gcc(14) gccBaseline/contrib/compare_tests 
gbBaseline/gcc/testsuite/gfortran/gfortran.log 
gbWide/gcc/testsuite/gfortran/gfortran.log
New tests that PASS:

gfortran.dg/pr32627.f03  -O3 -fomit-frame-pointer -funroll-loops (test 
for excess errors)
gfortran.dg/pr32627.f03  -O3 -fomit-frame-pointer  (test for excess errors)
gfortran.dg/pr32627.f03  -Os  (test for excess errors)
gfortran.dg/pr32635.f  -O0  execution test
gfortran.dg/pr32635.f  -O0  (test for excess errors)
gfortran.dg/substr_6.f90  -O2  (test for excess errors)

Old tests that passed, that have disappeared: (Eeek!)

gfortran.dg/pr32627.f03  -O1  (test for excess errors)
gfortran.dg/pr32627.f03  -O3 -fomit-frame-pointer -funroll-all-loops 
-finline-functions  (test for excess errors)
gfortran.dg/pr32627.f03  -O3 -g  (test for excess errors)
gfortran.dg/substring_equivalence.f90  -O  (test for excess errors)
Using /home/zadeck/gcc/gccBaseline/gcc/testsuite/config/default.exp as 
tool-and-target-specific interface file.

         === g++ Summary ===

# of expected passes        49793
# of expected failures        284
# of unsupported tests        601

runtest completed at Fri Oct  5 16:10:20 2012
heracles:~/gcc(16) tail gbWide/gcc/testsuite/g++/g++.log Using 
/usr/share/dejagnu/config/unix.exp as generic interface file for target.
Using /home/zadeck/gcc/gccWide/gcc/testsuite/config/default.exp as 
tool-and-target-specific interface file.

         === g++ Summary ===

# of expected passes        50472
# of expected failures        284
# of unsupported tests        613

runtest completed at Fri Oct  5 19:51:50 2012





^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-05 16:34                           ` Kenneth Zadeck
  2012-10-05 17:29                             ` Richard Sandiford
@ 2012-10-07 12:47                             ` Richard Guenther
  2012-10-07 13:11                               ` Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Guenther @ 2012-10-07 12:47 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, rdsandiford

On Fri, Oct 5, 2012 at 6:34 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> richard s,
> there are two comments that i deferred to you.   that have the word richard
> in them,
>
> richi,
> thank, i will start doing this now.
>
> kenny
>
> On 10/05/2012 09:49 AM, Richard Guenther wrote:
>>
>> On Fri, Oct 5, 2012 at 2:39 PM, Richard Guenther
>> <richard.guenther@gmail.com> wrote:
>>>
>>> Ok, I see where you are going.  Let me look at the patch again.
>>
>> * The introduction and use of CONST_SCALAR_INT_P could be split out
>>    (obvious and good)
>>
>> * DEF_RTL_EXPR(CONST_WIDE_INT, "const_wide_int", "", RTX_CONST_OBJ)
>>    defining that new RTX is orthogonal to providing the wide_int
>> abstraction
>>    for operating on CONST_INT and CONST_DOUBLE, right?
>>
>> @@ -144,6 +144,7 @@ static bool
>>   prefer_and_bit_test (enum machine_mode mode, int bitnum)
>>   {
>>     bool speed_p;
>> +  wide_int mask = wide_int::set_bit_in_zero (bitnum, mode);
>>
>> set_bit_in_zero ... why use this instead of
>> wide_int::zero (mode).set_bit (bitnum) that would match the old
>> double_int_zero.set_bit interface and be more composed of primitives?
>
> adding something like this was just based on usage.    We do this operation
> all over the place, why not make it concise and efficient.     The api is
> very bottom up.   I looked at what the clients were doing all over the place
> and added those functions.
>
> wide-int has both and_not and or_not.   double-int only has and_not, but
> there are a lot of places in where you do or_nots, so we have or_not also.
>
>
>>     if (and_test == 0)
>>       {
>> @@ -164,8 +165,7 @@ prefer_and_bit_test (enum machine_mode m
>>       }
>>
>>     /* Fill in the integers.  */
>> -  XEXP (and_test, 1)
>> -    = immed_double_int_const (double_int_zero.set_bit (bitnum), mode);
>> +  XEXP (and_test, 1) = immed_wide_int_const (mask);
>>
>> I suppose immed_wide_int_const may create a CONST_INT, a CONST_DOUBLE
>> or a CONST_WIDE_INT?
>
> yes, on converted targets it builds const_ints and const_wide_ints and on
> unconverted targets it builds const_ints and const_doubles.    The reason i
> did not want to convert the targets is that the code that lives in the
> targets generally wants to use the values to create constants and this code
> is very very very target specific.
>
>>
>> +#if TARGET_SUPPORTS_WIDE_INT
>> +/* Returns 1 if OP is an operand that is a CONST_INT or CONST_WIDE_INT.
>> */
>> +int
>> +const_scalar_int_operand (rtx op, enum machine_mode mode)
>> +{
>>
>> why is it necessary to condition anything on TARGET_SUPPORTS_WIDE_INT?
>> It seems testing/compile coverage of this code will be bad ...
>>
>> Can't you simply map CONST_WIDE_INT to CONST_DOUBLE for targets
>
> The accessors for the two are completely different.    const doubles "know"
> that there are exactly two hwi's.   for const_wide_ints, you only know that
> the len is greater than 1.   anything with len 1 would be CONST_INT.
>
> In a modern c++ world, const_int would be a subtype of const_int, but that
> is a huge patch.
>
>
>> not supporting CONST_WIDE_INT (what does it mean to "support"
>> CONST_WIDE_INT?  Does a target that supports CONST_WIDE_INT no
>> longer use CONST_DOUBLEs for integers?)
>
> yes, that is exactly what it means.
>
>> +  if (!CONST_WIDE_INT_P (op))
>> +    return 0;
>>
>> hm, that doesn't match the comment (CONST_INT is supposed to return 1 as
>> well).
>> The comment doesn't really tell what the function does it seems,
>
> I need some context here to reply.
>
>
>> +      int prec = GET_MODE_PRECISION (mode);
>> +      int bitsize = GET_MODE_BITSIZE (mode);
>> +
>> +      if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
>> +       return 0;
>>
>> it's mode argument is not documented.  And this doesn't even try to see if
>> the constant would fit the mode anyway (like if it's zero).  Not sure what
>> the function is for.
>
> I will upgrade the comments, they were inherited from the old version with
> the const_double changed to the const_wide_int
>
>
>> +       {
>> +         /* Multiword partial int.  */
>> +         HOST_WIDE_INT x
>> +           = CONST_WIDE_INT_ELT (op, CONST_WIDE_INT_NUNITS (op) - 1);
>> +         return (wide_int::sext (x, prec & (HOST_BITS_PER_WIDE_INT - 1))
>> +                 == x);
>>
>> err - so now we have wide_int with a mode but we pass in another mode
>> and see if they have the same value?  Same value as-in signed value?
>> Which probably is why you need to rule out different size constants above?
>> Because you don't know whether to sign or zero extend?
>
> no it is worse than that.   I made the decision, which i think is correct,
> that we were not going to carry the mode inside const_wide_int.   The
> justification was that we do not do it for const_int.    There is a comment
> in the constructor for const_wide_int that says it would be so easy to just
> put this in.
>
> But, this is an old api that did not change.   only the internals changed to
> support const_wide_int.
>
>
>>
>> +/* Returns 1 if OP is an operand that is a CONST_WIDE_INT.  */
>> +int
>> +const_wide_int_operand (rtx op, enum machine_mode mode)
>> +{
>>
>> similar comments, common code should be factored out at least.
>> Instead of conditioning a whole set of new function on supports-wide-int
>> please add cases to the existing functions to avoid diverging in pieces
>> that both kind of targets support.
>
> in some places i do one and in some i do the other.   it really just depends
> on how much common code there was.   For these there was almost no common
> code.
>
>
>> @@ -2599,7 +2678,7 @@ constrain_operands (int strict)
>>                  break;
>>
>>                case 'n':
>> -               if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
>> +               if (CONST_SCALAR_INT_P (op))
>>                    win = 1;
>>
>> factoring out this changes would really make the patch less noisy.
>
> i will this weekend.
>
>> skipping to rtl.h bits
>>
>> +struct GTY((variable_size)) hwivec_def {
>> +  int num_elem;                /* number of elements */
>> +  HOST_WIDE_INT elem[1];
>> +};
>>
>> num_elem seems redundant and computable from GET_MODE_SIZE.
>
> NOT AT ALL.   CONST_WIDE_INT and TREE_INT_CST only have enough elements in
> the array to hold the actual value, they do not have enough elements to hold
> the mode or type.
> in real life almost all integer constants of any type are very small.    in
> the rtl word, we almost never actually create any CONST_WIDE_INT outside of
> the test cases, because CONST_INT handles the cases, and i assume that at
> the tree level, almost every int cst will have an len of 1.
>
>
>
>> Or do you want to optimize encoding like for CONST_INT (and unlike
>> CONST_DOUBLE)?  I doubt the above packs nicely into rtx_def?
>> A general issue of it though - we waste 32bits on 64bit hosts in
>> rtx_def between the bits and the union.  Perfect place for num_elem
>> (if you really need it) and avoids another 4 byte hole.  Similar issue
>> exists in rtvec_def.
>
> I am going to let richard answer this.
>
>
>> back to where I was
>>
>> @@ -645,6 +673,10 @@ iterative_hash_rtx (const_rtx x, hashval
>>         return iterative_hash_object (i, hash);
>>       case CONST_INT:
>>         return iterative_hash_object (INTVAL (x), hash);
>> +    case CONST_WIDE_INT:
>> +      for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
>> +       hash = iterative_hash_object (CONST_WIDE_INT_ELT (x, i), hash);
>> +      return hash;
>>
>> I see CONST_DOUBLEs value is not hashed.  Why hash wide-ints value?
>
> There are a lot of ugly things that one uncovers when one looks at code this
> old.
> the idea was to bring whatever i touched up to best practice standards.
>
>
>> Seeing
>>
>> +#define HWI_GET_NUM_ELEM(HWIVEC)       ((HWIVEC)->num_elem)
>> +#define HWI_PUT_NUM_ELEM(HWIVEC, NUM)  ((HWIVEC)->num_elem = (NUM))
>>
>> skipping to
>>
>> +#if TARGET_SUPPORTS_WIDE_INT
>> +  {
>> +    rtx value = const_wide_int_alloc (len);
>> +    unsigned int i;
>> +
>> +    /* It is so tempting to just put the mode in here.  Must control
>> +       myself ... */
>> +    PUT_MODE (value, VOIDmode);
>> +    HWI_PUT_NUM_ELEM (CONST_WIDE_INT_VEC (value), len);
>>
>> why is NUM_ELEM not set in const_wide_int_alloc, and only there?
>>
>> +extern rtx rtx_alloc_stat_v (RTX_CODE MEM_STAT_DECL, int);
>> +#define rtx_alloc_v(c, SZ) rtx_alloc_stat_v (c MEM_STAT_INFO, SZ)
>> +#define const_wide_int_alloc(NWORDS)                           \
>> +  rtx_alloc_v (CONST_WIDE_INT,                                 \
>> +              (sizeof (struct hwivec_def)                      \
>> +               + ((NWORDS)-1) * sizeof (HOST_WIDE_INT)))       \
>>
>> because it's a macro(?).  Ugh.
>>
>> I see CONST_DOUBLE for ints and CONST_WIDE_INT for ints use
>> is mutually exclusive.  Good.  What's the issue with converting targets?
>> Just retain the existing 2 * HWI limit by default.
>
> I have answered this elsewhere, the constant generation code on some
> platforms is tricky and i felt that would require knowledge of the port that
> i did not have.   it is not just a bunch of c code, it is also changing
> patterns in the md files.
>
>
>> +#if TARGET_SUPPORTS_WIDE_INT
>> +
>> +/* Match CONST_*s that can represent compile-time constant integers.  */
>> +#define CASE_CONST_SCALAR_INT \
>> +   case CONST_INT: \
>> +   case CONST_WIDE_INT
>> +
>>
>> I regard this abstraction is mostly because the transition is not
>> finished.
>> Not sure if seeing CASE_CONST_SCALAR_INT, CASE_CONST_UNIQUE (?),
>> CASE_CONST_ANY adds more to the confusion than spelling out all of them.
>> Isn't there sth like a tree-code-class for RTXen?  That would catch
>> CASE_CONST_ANY, no?
>
> however, those abstractions are already in the trunk.   They were put in
> earlier to make this patch smaller.
>
>> @@ -3081,6 +3081,8 @@ commutative_operand_precedence (rtx op)
>>     /* Constants always come the second operand.  Prefer "nice" constants.
>> */
>>     if (code == CONST_INT)
>>       return -8;
>> +  if (code == CONST_WIDE_INT)
>> +    return -8;
>>     if (code == CONST_DOUBLE)
>>       return -7;
>>     if (code == CONST_FIXED)
>>
>> I think it should be the same as CONST_DOUBLE which it "replaces".
>> Likewise below, that avoids code generation changes (which there should
>> be none for a target that is converted, right?).
>
> not clear because it does not really replace const double - remember that
> const double still holds fp stuff.    another one for richard to comment on.
>
>> @@ -5351,6 +5355,20 @@ split_double (rtx value, rtx *first, rtx
>>              }
>>          }
>>       }
>> +  else if (GET_CODE (value) == CONST_WIDE_INT)
>> +    {
>> +      gcc_assert (CONST_WIDE_INT_NUNITS (value) == 2);
>> +      if (WORDS_BIG_ENDIAN)
>> +       {
>> +         *first = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
>> +         *second = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
>> +       }
>> +      else
>> +       {
>> +         *first = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
>> +         *second = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
>> +       }
>> +    }
>>
>> scary ;)
>
> unbelievably scary.    This is one of those places where i really do not
> know what the code is doing and so i just put in something that was
> minimally correct.    when we get some code where the assert hits then i
> will figure it out.
>
>
>> Index: gcc/sched-vis.c
>> ===================================================================
>> --- gcc/sched-vis.c     (revision 191978)
>> +++ gcc/sched-vis.c     (working copy)
>> @@ -444,14 +444,31 @@ print_value (char *buf, const_rtx x, int
>> ...
>>       case CONST_DOUBLE:
>> -      if (FLOAT_MODE_P (GET_MODE (x)))
>> -       real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0,
>> 1);
>> -      else
>> +     if (TARGET_SUPPORTS_WIDE_INT == 0 && !FLOAT_MODE_P (GET_MODE (x)))
>>          sprintf (t,
>>                   "<" HOST_WIDE_INT_PRINT_HEX "," HOST_WIDE_INT_PRINT_HEX
>> ">",
>>                   (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x),
>>                   (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x));
>> +      else
>> +       real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0,
>> 1);
>>         cur = safe_concat (buf, cur, t);
>>         break;
>>
>> I don't see that this hunk is needed?  In fact it's more confusing this
>> way.
>
> you are likely right.   this is really there to say that this code would go
> away if
> (when) all targets support wide int,  but i will get rid of it.
>
>> +/* If the target supports integers that are wider than two
>> +   HOST_WIDE_INTs on the host compiler, then the target should define
>> +   TARGET_SUPPORTS_WIDE_INT and make the appropriate fixups.
>> +   Otherwise the compiler really is not robust.  */
>> +#ifndef TARGET_SUPPORTS_WIDE_INT
>> +#define TARGET_SUPPORTS_WIDE_INT 0
>> +#endif
>>
>> I wonder what are the appropriate fixups?
>
> it was in the mail of the original patch.    i will in the next round,
> transfer a cleaned up version of that into the doc for this target hook.
>
>>
>> -/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
>> -   GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
>> +/* Return a CONST_INT, CONST_WIDE_INT, or CONST_DOUBLE corresponding
>> +   to target reading GET_MODE_BITSIZE (MODE) bits from string constant
>> +   STR.  */
>>
>> maybe being less specific in this kind of comments and just refering to
>> RTX integer constants would be better?
>
> will do, i have done some like that.
>
>> ... skip ...
>>
>> Index: gcc/hwint.c
>> ===================================================================
>> --- gcc/hwint.c (revision 191978)
>> +++ gcc/hwint.c (working copy)
>> @@ -112,6 +112,29 @@ ffs_hwi (unsigned HOST_WIDE_INT x)
>>   int
>>   popcount_hwi (unsigned HOST_WIDE_INT x)
>>   {
>> +  /* Compute the popcount of a HWI using the algorithm from
>> +     Hacker's Delight.  */
>> +#if HOST_BITS_PER_WIDE_INT == 32
>>
>> separate patch please.  With a rationale.
>
> fine.
>
>> ...
>>
>> +/* Constructs tree in type TYPE from with value given by CST.  Signedness
>> +   of CST is assumed to be the same as the signedness of TYPE.  */
>> +
>> +tree
>> +wide_int_to_tree (tree type, const wide_int &cst)
>> +{
>> +  wide_int v;
>> +  if (TYPE_UNSIGNED (type))
>> +    v = cst.zext (TYPE_PRECISION (type));
>> +  else
>> +    v = cst.sext (TYPE_PRECISION (type));
>> +
>> +  return build_int_cst_wide (type, v.elt (0), v.elt (1));
>>
>> this needs an assert that the wide-int contains two HWIs.
>
> as i said in an earlier mail, this is just transition code for when the tree
> level code goes in.
> but i see your point and will add the assert.
>
>
>
>> +#ifndef GENERATOR_FILE
>> +extern tree wide_int_to_tree (tree type, const wide_int &cst);
>> +#endif
>>
>> why's that?  The header inclusion isn't guarded that way.
>
> there was a problem building without it.   but i will look into it.
>
>> Stopping here, skipping to wide-int.[ch]
>>
>> +#define DEBUG_WIDE_INT
>> +#ifdef DEBUG_WIDE_INT
>> +  /* Debugging routines.  */
>> +  static void debug_vw  (const char* name, int r, const wide_int& o0);
>> +  static void debug_vwh (const char* name, int r, const wide_int &o0,
>> +                        HOST_WIDE_INT o1);
>>
>> there is DEBUG_FUNCTION.
>>
>> +/* This is the maximal size of the buffer needed for dump.  */
>> +const int MAX = (MAX_BITSIZE_MODE_ANY_INT / 4
>> +                + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT +
>> 32);
>>
>> I'd prefer a target macro for this, not anything based off
>> MAX_BITSIZE_MODE_ANY_INT just to allow no-op transition of a
>> target to wide-ints (which IMHO should be the default for all targets,
>> simplifying the patch).
>>
>> +wide_int
>> +wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode
>> mode, bool *overflow)
>> +{
>> ...
>> +#ifdef DEBUG_WIDE_INT
>> +  if (dump_file)
>> +    {
>> +      char buf0[MAX];
>> +      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
>> +              "wide_int::from_uhwi", result.dump (buf0), op0);
>> +    }
>> +#endif
>>
>> hm, ok ... I suppose the debug stuff (which looks very noisy) is going to
>> be
>> removed before this gets committed anywhere?
>
> it is very noisy and i was just planning to turn it off.    but it is very
> useful when there is a problem so i was not planning to actually remove it
> immediately.
>
>
>>
>> +wide_int
>> +wide_int::from_int_cst (const_tree tcst)
>> +{
>> +#if 1
>> +  wide_int result;
>> +  tree type = TREE_TYPE (tcst);
>>
>> should just call wide_it::from_double_int (tree_to_double_int (tcst))
>>
>> As I said elsewhere I don't think only allowing precisions that are
>> somewhere
>> in any mode is good enough.  We need the actual precision here
>> (everywhere).
>
> i think that the case has been made that what wide int needs to store inside
> it is the precision and bitsize and that passing in the mode/tree type is
> just a convenience.     I will make this change. Then we can have exposed
> constructors that just take bitsize and precision.
>
>
>
>> Index: gcc/wide-int.h
>> ===================================================================
>> --- gcc/wide-int.h      (revision 0)
>> +++ gcc/wide-int.h      (revision 0)
>> @@ -0,0 +1,718 @@
>> +/* Operations with very long integers.
>> +   Copyright (C) 2012 Free Software Foundation, Inc.
>> ...
>> +
>> +#ifndef GENERATOR_FILE
>> +#include "hwint.h"
>> +#include "options.h"
>> +#include "tm.h"
>> +#include "insn-modes.h"
>> +#include "machmode.h"
>> +#include "double-int.h"
>> +#include <gmp.h>
>> +#include "insn-modes.h"
>>
>> ugh.  Compare this with double-int.h which just needs <gmp.h> (and even
>> that
>> is a red herring) ...
>>
>> +#define wide_int_minus_one(MODE) (wide_int::from_shwi (-1, MODE))
>> +#define wide_int_zero(MODE)      (wide_int::from_shwi (0, MODE))
>> +#define wide_int_one(MODE)       (wide_int::from_shwi (1, MODE))
>> +#define wide_int_two(MODE)       (wide_int::from_shwi (2, MODE))
>> +#define wide_int_ten(MODE)       (wide_int::from_shwi (10, MODE))
>>
>> add static functions like
>>
>>    wide_int wide_int::zero (MODE)
>
> ok
>
>> +class wide_int {
>> +  /* Internal representation.  */
>> +  HOST_WIDE_INT val[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
>> +  unsigned short len;
>> +  enum machine_mode mode;
>>
>> you really need to store the precision here, not the mode.  We do not have
>> a distinct mode for each of the tree constant precisions we see.  So what
>> might work for RTL will later fail on trees, so better do it correct
>> from the start
>> (overloads using mode rather than precision may be acceptable - similarly
>> I'd consider overloads for tree types).
>
> discussed above.
>
>> len seems redundant unless you want to optimize encoding.
>> len == (precision + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT.
>
> that is exactly what we do.   However, we are optimizing time, not space.
> the value is always stored in compressed form, i.e the same representation
> as is used inside the CONST_WIDE_INTs and INT_CSTs. this makes the
> transformation between them very fast.   And since we do this a lot, it
> needs to be fast.   So the len is the number of HWIs needed to represent the
> value which is typically less than what would be implied by the precision.

But doesn't this require a sign?  Otherwise how do you encode TImode 0xffffffff?
Would len be 1 here?  (and talking about CONST_WIDE_INT vs CONST_INT,
wouldn't CONST_INT be used anyway for all ints we can encode "small"?  Or
is it (hopefully) the goal to replace CONST_INT with CONST_WIDE_INT
everywhere?)  Or do you say wide_int is always "signed', thus TImode 0xffffffff
needs len == 2 and an explicit zero upper HWI word?  Or do you say wide_int
is always "unsigned", thus TImode -1 needs len == 2?  Noting that double-ints
were supposed to be twos-complement (thus, 'unsigned') numbers having
implicit non-zero bits sounds error-prone.

That said - I don't see any value in optimizing storage for short-lived
(as you say) wide-ints (apart from limiting it to the mode size).  For
example mutating operations on wide-ints are not really possible
if you need to extend storage.

>> +  enum Op {
>> +    NONE,
>>
>> we don't have sth like this in double-int.h, why was the double-int
>> mechanism
>> not viable?
>
> i have chosen to use enums for things rather than passing booleans.

But it's bad to use an enum with 4 values for a thing that can only possibly
expect two.  You cannot optimize tests as easily.  Please retain the bool uns
parameters instead.

Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-07 12:47                             ` patch to fix constant math Richard Guenther
@ 2012-10-07 13:11                               ` Kenneth Zadeck
  2012-10-07 13:19                                 ` Richard Guenther
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-07 13:11 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Mike Stump, gcc-patches, rdsandiford


On 10/07/2012 08:47 AM, Richard Guenther wrote:
>>> len seems redundant unless you want to optimize encoding.
>>> >>len == (precision + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT.
>> >
>> >that is exactly what we do.   However, we are optimizing time, not space.
>> >the value is always stored in compressed form, i.e the same representation
>> >as is used inside the CONST_WIDE_INTs and INT_CSTs. this makes the
>> >transformation between them very fast.   And since we do this a lot, it
>> >needs to be fast.   So the len is the number of HWIs needed to represent the
>> >value which is typically less than what would be implied by the precision.
> But doesn't this require a sign?  Otherwise how do you encode TImode 0xffffffff?
> Would len be 1 here?  (and talking about CONST_WIDE_INT vs CONST_INT,
> wouldn't CONST_INT be used anyway for all ints we can encode "small"?  Or
> is it (hopefully) the goal to replace CONST_INT with CONST_WIDE_INT
> everywhere?)  Or do you say wide_int is always "signed', thus TImode 0xffffffff
> needs len == 2 and an explicit zero upper HWI word?
the compression of this has len ==2 with the explicit upper being 0.

>   Or do you say wide_int
> is always "unsigned", thus TImode -1 needs len == 2?  Noting that double-ints
> were supposed to be twos-complement (thus, 'unsigned') numbers having
> implicit non-zero bits sounds error-prone.
>
> That said - I don't see any value in optimizing storage for short-lived
> (as you say) wide-ints (apart from limiting it to the mode size).  For
> example mutating operations on wide-ints are not really possible
> if you need to extend storage.
the compression used is independent of whether it is sign or unsigned.  
but the compression "looks" signed.   i.e. you do not represent the 
upper hwi if they would just be a sign extension of the top hwi that is 
represented.   However, this does not imply anything about the math that 
was used to set those bits that way, and you can always go back to the 
full rep independent of the sign.

I do not have any long term plans to merge CONST_INT into 
CONST_WIDE_INT.   It would be a huge change in the ports and would be 
fairly space inefficient.  My guess is that in real code, less than 1% 
of real constants will have a length greater than 1 even on a 32 bit 
host.   CONST_INT is very space efficient. This could have been 
mentioned as part of Richard's response to your comment about the way we 
represent the CONST_WIDE_INTs.   In practice, there are almost none of 
them anyway.

In fact, you could argue that the tree level did it wrong (not that i am 
suggesting to change this).   But it makes me think what was going on 
when the decision to make TYPE_PRECISION be an INT_CST rather than just 
a HWI was made.   For that there is an implication that it could never 
take more than a HWI since no place in the code even checks 
TREE_INT_CST_HIGH for these.
>>> >>+  enum Op {
>>> >>+    NONE,
>>> >>
>>> >>we don't have sth like this in double-int.h, why was the double-int
>>> >>mechanism
>>> >>not viable?
>> >
>> >i have chosen to use enums for things rather than passing booleans.
> But it's bad to use an enum with 4 values for a thing that can only possibly
> expect two.  You cannot optimize tests as easily.  Please retain the bool uns
> parameters instead.
I am breaking it into two enums.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-07 13:11                               ` Kenneth Zadeck
@ 2012-10-07 13:19                                 ` Richard Guenther
  2012-10-07 14:58                                   ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Guenther @ 2012-10-07 13:19 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, rdsandiford

On Sun, Oct 7, 2012 at 3:11 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>
> On 10/07/2012 08:47 AM, Richard Guenther wrote:
>>>>
>>>> len seems redundant unless you want to optimize encoding.
>>>> >>len == (precision + HOST_BITS_PER_WIDE_INT - 1) /
>>>> >> HOST_BITS_PER_WIDE_INT.
>>>
>>> >
>>> >that is exactly what we do.   However, we are optimizing time, not
>>> > space.
>>> >the value is always stored in compressed form, i.e the same
>>> > representation
>>> >as is used inside the CONST_WIDE_INTs and INT_CSTs. this makes the
>>> >transformation between them very fast.   And since we do this a lot, it
>>> >needs to be fast.   So the len is the number of HWIs needed to represent
>>> > the
>>> >value which is typically less than what would be implied by the
>>> > precision.
>>
>> But doesn't this require a sign?  Otherwise how do you encode TImode
>> 0xffffffff?
>> Would len be 1 here?  (and talking about CONST_WIDE_INT vs CONST_INT,
>> wouldn't CONST_INT be used anyway for all ints we can encode "small"?  Or
>> is it (hopefully) the goal to replace CONST_INT with CONST_WIDE_INT
>> everywhere?)  Or do you say wide_int is always "signed', thus TImode
>> 0xffffffff
>> needs len == 2 and an explicit zero upper HWI word?
>
> the compression of this has len ==2 with the explicit upper being 0.
>
>
>>   Or do you say wide_int
>> is always "unsigned", thus TImode -1 needs len == 2?  Noting that
>> double-ints
>> were supposed to be twos-complement (thus, 'unsigned') numbers having
>> implicit non-zero bits sounds error-prone.
>>
>> That said - I don't see any value in optimizing storage for short-lived
>> (as you say) wide-ints (apart from limiting it to the mode size).  For
>> example mutating operations on wide-ints are not really possible
>> if you need to extend storage.
>
> the compression used is independent of whether it is sign or unsigned.  but
> the compression "looks" signed.   i.e. you do not represent the upper hwi if
> they would just be a sign extension of the top hwi that is represented.
> However, this does not imply anything about the math that was used to set
> those bits that way, and you can always go back to the full rep independent
> of the sign.
>
> I do not have any long term plans to merge CONST_INT into CONST_WIDE_INT.
> It would be a huge change in the ports and would be fairly space
> inefficient.  My guess is that in real code, less than 1% of real constants
> will have a length greater than 1 even on a 32 bit host.   CONST_INT is very
> space efficient. This could have been mentioned as part of Richard's
> response to your comment about the way we represent the CONST_WIDE_INTs.
> In practice, there are almost none of them anyway.
>
> In fact, you could argue that the tree level did it wrong (not that i am
> suggesting to change this).   But it makes me think what was going on when
> the decision to make TYPE_PRECISION be an INT_CST rather than just a HWI was
> made.   For that there is an implication that it could never take more than
> a HWI since no place in the code even checks TREE_INT_CST_HIGH for these.

Well - on the tree level we now always have two HWIs for all INTEGER_CSTs.  If
we can, based on the size of the underlying mode, reduce that to one
HWI we already
win something.  If we add an explicit length to allow a smaller
encoding for larger modes
(tree_base conveniently has an available 'int' for this ...) then we'd
win in more cases.
Thus, is CONST_INT really necessarily better than optimized CONST_WIDE_INT
storage?

Richard.

>>>> >>+  enum Op {
>>>> >>+    NONE,
>>>> >>
>>>> >>we don't have sth like this in double-int.h, why was the double-int
>>>> >>mechanism
>>>> >>not viable?
>>>
>>> >
>>> >i have chosen to use enums for things rather than passing booleans.
>>
>> But it's bad to use an enum with 4 values for a thing that can only
>> possibly
>> expect two.  You cannot optimize tests as easily.  Please retain the bool
>> uns
>> parameters instead.
>
> I am breaking it into two enums.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-07 13:19                                 ` Richard Guenther
@ 2012-10-07 14:58                                   ` Kenneth Zadeck
  2012-10-08  9:27                                     ` Richard Guenther
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-07 14:58 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Mike Stump, gcc-patches, rdsandiford


On 10/07/2012 09:19 AM, Richard Guenther wrote:
>> >In fact, you could argue that the tree level did it wrong (not that i am
>> >suggesting to change this).   But it makes me think what was going on when
>> >the decision to make TYPE_PRECISION be an INT_CST rather than just a HWI was
>> >made.   For that there is an implication that it could never take more than
>> >a HWI since no place in the code even checks TREE_INT_CST_HIGH for these.
> Well - on the tree level we now always have two HWIs for all INTEGER_CSTs.  If
> we can, based on the size of the underlying mode, reduce that to one
> HWI we already
> win something.  If we add an explicit length to allow a smaller
> encoding for larger modes
> (tree_base conveniently has an available 'int' for this ...) then we'd
> win in more cases.
> Thus, is CONST_INT really necessarily better than optimized CONST_WIDE_INT
> storage?
i have to admit, that looking at these data structures gives me a 
headache.  This all looks like something that Rube Goldberg would have 
invented had he done object oriented design  (Richard S did not know who 
Rube Goldberg when i mentioned this name to him a few years ago since 
this is an American thing, but the british had their own equivalent and 
I assume the germans do too.).

i did the first cut of changing the rtl level structure and Richard S 
threw up on it and suggested what is there now, which happily (for me) i 
was able to get mike to implement.

mike also did the tree level version of the data structures for me.   i 
will make sure he used that left over length field.

The bottom line is that you most likely just save the length, but that 
is a big percent of something this small.  Both of rtl ints have a mode, 
so if we can make that change later, it will be space neutral.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - second small patch
  2012-10-05 22:48                                 ` patch to fix constant math - second " Kenneth Zadeck
  2012-10-06 15:55                                   ` patch to fix constant math - third " Kenneth Zadeck
@ 2012-10-08  9:07                                   ` Richard Guenther
  2012-11-08 18:14                                     ` Kenneth Zadeck
  2013-02-27  0:28                                   ` patch to fix constant math - second small patch -patch ping for next stage 1 Kenneth Zadeck
  2 siblings, 1 reply; 217+ messages in thread
From: Richard Guenther @ 2012-10-08  9:07 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, rdsandiford

On Sat, Oct 6, 2012 at 12:48 AM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
> This patch adds machinery to genmodes.c so that largest possible sizes of
> various data structures can be determined at gcc build time.  These
> functions create 3 symbols that are available in insn-modes.h:
> MAX_BITSIZE_MODE_INT - the bitsize of the largest int.
> MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int.
> MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int.

Ok.  Please document these macros in rtl.texi.

Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - third small patch
  2012-10-06 15:55                                   ` patch to fix constant math - third " Kenneth Zadeck
@ 2012-10-08  9:08                                     ` Richard Guenther
  2012-10-08 11:37                                     ` Kenneth Zadeck
  1 sibling, 0 replies; 217+ messages in thread
From: Richard Guenther @ 2012-10-08  9:08 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, rdsandiford

On Sat, Oct 6, 2012 at 5:55 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> This is the third patch in the series of patches to fix constant math.
> this one changes some predicates at the rtl level to use the new predicate
> CONST_SCALAR_INT_P.
> I did not include a few that were tightly intertwined with other changes.
>
> Not all of these changes are strictly mechanical.   Richard, when reviewing
> this had me make additional changes to remove what he thought were latent
> bugs at the rtl level.   However, it appears that the bugs were not latent.
> I do not know what is going on here but i am smart enough to not look a gift
> horse in the mouth.
>
> All of this was done on the same machine with no changes and identical
> configs.  It is an x86-64 with ubuntu 12-4.
>
> ok for commit?

Patch missing, but if it's just mechanical changes and introduction
of CONST_SCALAR_INT_P consider it pre-approved.

Richard.

> in the logs below, gbBaseline is a trunk from friday and the gbWide is the
> same revision but with my patches.  Some of this like gfortran.dg/pr32627 is
> obviously flutter, but the rest does not appear to be.
>
> =========
> heracles:~/gcc(13) gccBaseline/contrib/compare_tests
> gbBaseline/gcc/testsuite/gcc/gcc.log gbWide/gcc/testsuite/gcc/gcc.log
> New tests that PASS:
>
> gcc.dg/builtins-85.c scan-assembler mysnprintf
> gcc.dg/builtins-85.c scan-assembler-not __chk_fail
> gcc.dg/builtins-85.c (test for excess errors)
>
>
> heracles:~/gcc(14) gccBaseline/contrib/compare_tests
> gbBaseline/gcc/testsuite/gfortran/gfortran.log
> gbWide/gcc/testsuite/gfortran/gfortran.log
> New tests that PASS:
>
> gfortran.dg/pr32627.f03  -O3 -fomit-frame-pointer -funroll-loops (test for
> excess errors)
> gfortran.dg/pr32627.f03  -O3 -fomit-frame-pointer  (test for excess errors)
> gfortran.dg/pr32627.f03  -Os  (test for excess errors)
> gfortran.dg/pr32635.f  -O0  execution test
> gfortran.dg/pr32635.f  -O0  (test for excess errors)
> gfortran.dg/substr_6.f90  -O2  (test for excess errors)
>
> Old tests that passed, that have disappeared: (Eeek!)
>
> gfortran.dg/pr32627.f03  -O1  (test for excess errors)
> gfortran.dg/pr32627.f03  -O3 -fomit-frame-pointer -funroll-all-loops
> -finline-functions  (test for excess errors)
> gfortran.dg/pr32627.f03  -O3 -g  (test for excess errors)
> gfortran.dg/substring_equivalence.f90  -O  (test for excess errors)
> Using /home/zadeck/gcc/gccBaseline/gcc/testsuite/config/default.exp as
> tool-and-target-specific interface file.
>
>         === g++ Summary ===
>
> # of expected passes        49793
> # of expected failures        284
> # of unsupported tests        601
>
> runtest completed at Fri Oct  5 16:10:20 2012
> heracles:~/gcc(16) tail gbWide/gcc/testsuite/g++/g++.log Using
> /usr/share/dejagnu/config/unix.exp as generic interface file for target.
> Using /home/zadeck/gcc/gccWide/gcc/testsuite/config/default.exp as
> tool-and-target-specific interface file.
>
>         === g++ Summary ===
>
> # of expected passes        50472
> # of expected failures        284
> # of unsupported tests        613
>
> runtest completed at Fri Oct  5 19:51:50 2012
>
>
>
>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-07 14:58                                   ` Kenneth Zadeck
@ 2012-10-08  9:27                                     ` Richard Guenther
  2012-10-08 15:01                                       ` Nathan Froyd
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Guenther @ 2012-10-08  9:27 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, rdsandiford

On Sun, Oct 7, 2012 at 4:58 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>
> On 10/07/2012 09:19 AM, Richard Guenther wrote:
>>>
>>> >In fact, you could argue that the tree level did it wrong (not that i am
>>> >suggesting to change this).   But it makes me think what was going on
>>> > when
>>> >the decision to make TYPE_PRECISION be an INT_CST rather than just a HWI
>>> > was
>>> >made.   For that there is an implication that it could never take more
>>> > than
>>> >a HWI since no place in the code even checks TREE_INT_CST_HIGH for
>>> > these.
>>
>> Well - on the tree level we now always have two HWIs for all INTEGER_CSTs.
>> If
>> we can, based on the size of the underlying mode, reduce that to one
>> HWI we already
>> win something.  If we add an explicit length to allow a smaller
>> encoding for larger modes
>> (tree_base conveniently has an available 'int' for this ...) then we'd
>> win in more cases.
>> Thus, is CONST_INT really necessarily better than optimized CONST_WIDE_INT
>> storage?
>
> i have to admit, that looking at these data structures gives me a headache.
> This all looks like something that Rube Goldberg would have invented had he
> done object oriented design  (Richard S did not know who Rube Goldberg when
> i mentioned this name to him a few years ago since this is an American
> thing, but the british had their own equivalent and I assume the germans do
> too.).
>
> i did the first cut of changing the rtl level structure and Richard S threw
> up on it and suggested what is there now, which happily (for me) i was able
> to get mike to implement.
>
> mike also did the tree level version of the data structures for me.   i will
> make sure he used that left over length field.
>
> The bottom line is that you most likely just save the length, but that is a
> big percent of something this small.  Both of rtl ints have a mode, so if we
> can make that change later, it will be space neutral.

Yes.

Btw, as for Richards idea of conditionally placing the length field in
rtx_def looks like overkill to me.  These days we'd merely want to
optimize for 64bit hosts, thus unconditionally adding a 32 bit
field to rtx_def looks ok to me (you can wrap that inside a union to
allow both descriptive names and eventual different use - see what
I've done to tree_base)

Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - third small patch
  2012-10-06 15:55                                   ` patch to fix constant math - third " Kenneth Zadeck
  2012-10-08  9:08                                     ` Richard Guenther
@ 2012-10-08 11:37                                     ` Kenneth Zadeck
  2012-10-08 12:11                                       ` Richard Guenther
  2012-10-08 19:43                                       ` Richard Sandiford
  1 sibling, 2 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-08 11:37 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Richard Guenther, Mike Stump, gcc-patches, rdsandiford

[-- Attachment #1: Type: text/plain, Size: 3062 bytes --]

yes, my bad.   here it is with the patches.
On 10/06/2012 11:55 AM, Kenneth Zadeck wrote:
> This is the third patch in the series of patches to fix constant math.
> this one changes some predicates at the rtl level to use the new 
> predicate CONST_SCALAR_INT_P.
> I did not include a few that were tightly intertwined with other changes.
>
> Not all of these changes are strictly mechanical.   Richard, when 
> reviewing this had me make additional changes to remove what he 
> thought were latent bugs at the rtl level.   However, it appears that 
> the bugs were not latent.    I do not know what is going on here but i 
> am smart enough to not look a gift horse in the mouth.
>
> All of this was done on the same machine with no changes and identical 
> configs.  It is an x86-64 with ubuntu 12-4.
>
> ok for commit?
>
> in the logs below, gbBaseline is a trunk from friday and the gbWide is 
> the same revision but with my patches.  Some of this like 
> gfortran.dg/pr32627 is obviously flutter, but the rest does not appear 
> to be.
>
> =========
> heracles:~/gcc(13) gccBaseline/contrib/compare_tests 
> gbBaseline/gcc/testsuite/gcc/gcc.log gbWide/gcc/testsuite/gcc/gcc.log
> New tests that PASS:
>
> gcc.dg/builtins-85.c scan-assembler mysnprintf
> gcc.dg/builtins-85.c scan-assembler-not __chk_fail
> gcc.dg/builtins-85.c (test for excess errors)
>
>
> heracles:~/gcc(14) gccBaseline/contrib/compare_tests 
> gbBaseline/gcc/testsuite/gfortran/gfortran.log 
> gbWide/gcc/testsuite/gfortran/gfortran.log
> New tests that PASS:
>
> gfortran.dg/pr32627.f03  -O3 -fomit-frame-pointer -funroll-loops (test 
> for excess errors)
> gfortran.dg/pr32627.f03  -O3 -fomit-frame-pointer  (test for excess 
> errors)
> gfortran.dg/pr32627.f03  -Os  (test for excess errors)
> gfortran.dg/pr32635.f  -O0  execution test
> gfortran.dg/pr32635.f  -O0  (test for excess errors)
> gfortran.dg/substr_6.f90  -O2  (test for excess errors)
>
> Old tests that passed, that have disappeared: (Eeek!)
>
> gfortran.dg/pr32627.f03  -O1  (test for excess errors)
> gfortran.dg/pr32627.f03  -O3 -fomit-frame-pointer -funroll-all-loops 
> -finline-functions  (test for excess errors)
> gfortran.dg/pr32627.f03  -O3 -g  (test for excess errors)
> gfortran.dg/substring_equivalence.f90  -O  (test for excess errors)
> Using /home/zadeck/gcc/gccBaseline/gcc/testsuite/config/default.exp as 
> tool-and-target-specific interface file.
>
>         === g++ Summary ===
>
> # of expected passes        49793
> # of expected failures        284
> # of unsupported tests        601
>
> runtest completed at Fri Oct  5 16:10:20 2012
> heracles:~/gcc(16) tail gbWide/gcc/testsuite/g++/g++.log Using 
> /usr/share/dejagnu/config/unix.exp as generic interface file for target.
> Using /home/zadeck/gcc/gccWide/gcc/testsuite/config/default.exp as 
> tool-and-target-specific interface file.
>
>         === g++ Summary ===
>
> # of expected passes        50472
> # of expected failures        284
> # of unsupported tests        613
>
> runtest completed at Fri Oct  5 19:51:50 2012
>
>
>
>
>


[-- Attachment #2: p3-1.diff --]
[-- Type: text/x-patch, Size: 15666 bytes --]

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 299150e..0404605 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -3633,9 +3633,8 @@ expand_debug_locations (void)
 
 	    gcc_assert (mode == GET_MODE (val)
 			|| (GET_MODE (val) == VOIDmode
-			    && (CONST_INT_P (val)
+			    && (CONST_SCALAR_INT_P (val)
 				|| GET_CODE (val) == CONST_FIXED
-				|| CONST_DOUBLE_AS_INT_P (val) 
 				|| GET_CODE (val) == LABEL_REF)));
 	  }
 
diff --git a/gcc/combine.c b/gcc/combine.c
index 4e0a579..b531305 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -2617,16 +2617,19 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
      constant.  */
   if (i1 == 0
       && (temp = single_set (i2)) != 0
-      && (CONST_INT_P (SET_SRC (temp))
-	  || CONST_DOUBLE_AS_INT_P (SET_SRC (temp)))
+      && CONST_SCALAR_INT_P (SET_SRC (temp))
       && GET_CODE (PATTERN (i3)) == SET
-      && (CONST_INT_P (SET_SRC (PATTERN (i3)))
-	  || CONST_DOUBLE_AS_INT_P (SET_SRC (PATTERN (i3))))
+      && CONST_SCALAR_INT_P (SET_SRC (PATTERN (i3)))
       && reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp)))
     {
       rtx dest = SET_DEST (PATTERN (i3));
       int offset = -1;
       int width = 0;
+      
+      /* There are not explicit tests to make sure that this is not a
+	 float, but there is code here that would not be correct if it
+	 was.  */
+      gcc_assert (GET_MODE_CLASS (GET_MODE (SET_SRC (temp))) != MODE_FLOAT);
 
       if (GET_CODE (dest) == ZERO_EXTRACT)
 	{
@@ -5102,8 +5105,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
 	      if (GET_CODE (new_rtx) == CLOBBER && XEXP (new_rtx, 0) == const0_rtx)
 		return new_rtx;
 
-	      if (GET_CODE (x) == SUBREG
-		  && (CONST_INT_P (new_rtx) || CONST_DOUBLE_AS_INT_P (new_rtx)))
+	      if (GET_CODE (x) == SUBREG && CONST_SCALAR_INT_P (new_rtx))
 		{
 		  enum machine_mode mode = GET_MODE (x);
 
@@ -7133,7 +7135,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
       if (mode == tmode)
 	return new_rtx;
 
-      if (CONST_INT_P (new_rtx) || CONST_DOUBLE_AS_INT_P (new_rtx))
+      if (CONST_SCALAR_INT_P (new_rtx))
 	return simplify_unary_operation (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
 					 mode, new_rtx, tmode);
 
@@ -10672,8 +10674,7 @@ gen_lowpart_for_combine (enum machine_mode omode, rtx x)
   /* We can only support MODE being wider than a word if X is a
      constant integer or has a mode the same size.  */
   if (GET_MODE_SIZE (omode) > UNITS_PER_WORD
-      && ! ((CONST_INT_P (x) || CONST_DOUBLE_AS_INT_P (x))
-	    || isize == osize))
+      && ! (CONST_SCALAR_INT_P (x) || isize == osize))
     goto fail;
 
   /* X might be a paradoxical (subreg (mem)).  In that case, gen_lowpart
diff --git a/gcc/cselib.c b/gcc/cselib.c
index e7c4221..e6550a3 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -534,17 +534,15 @@ entry_and_rtx_equal_p (const void *entry, const void *x_arg)
   rtx x = CONST_CAST_RTX ((const_rtx)x_arg);
   enum machine_mode mode = GET_MODE (x);
 
-  gcc_assert (!CONST_INT_P (x) && GET_CODE (x) != CONST_FIXED
-	      && (mode != VOIDmode || GET_CODE (x) != CONST_DOUBLE));
+  gcc_assert (!CONST_SCALAR_INT_P (x) && GET_CODE (x) != CONST_FIXED);
 
   if (mode != GET_MODE (v->val_rtx))
     return 0;
 
   /* Unwrap X if necessary.  */
   if (GET_CODE (x) == CONST
-      && (CONST_INT_P (XEXP (x, 0))
-	  || GET_CODE (XEXP (x, 0)) == CONST_FIXED
-	  || GET_CODE (XEXP (x, 0)) == CONST_DOUBLE))
+      && (CONST_SCALAR_INT_P (XEXP (x, 0))
+	  || GET_CODE (XEXP (x, 0)) == CONST_FIXED))
     x = XEXP (x, 0);
 
   /* We don't guarantee that distinct rtx's have different hash values,
@@ -1009,9 +1007,7 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, enum machine_mode memmode)
 static rtx
 wrap_constant (enum machine_mode mode, rtx x)
 {
-  if (!CONST_INT_P (x) 
-      && GET_CODE (x) != CONST_FIXED
-      && !CONST_DOUBLE_AS_INT_P (x))
+  if ((!CONST_SCALAR_INT_P (x)) && GET_CODE (x) != CONST_FIXED)
     return x;
   gcc_assert (mode != VOIDmode);
   return gen_rtx_CONST (mode, x);
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 95fc130..98c88f7 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -12351,8 +12351,8 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
 
     case CONST:
       if (mode == VOIDmode
-	  || GET_CODE (XEXP (rtl, 0)) == CONST_INT
-	  || GET_CODE (XEXP (rtl, 0)) == CONST_DOUBLE
+	  || CONST_SCALAR_INT_P (XEXP (rtl, 0))
+	  || CONST_DOUBLE_AS_FLOAT_P (XEXP (rtl, 0))
 	  || GET_CODE (XEXP (rtl, 0)) == CONST_VECTOR)
 	{
 	  loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index ee6ae22..bd6fc26 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1244,7 +1244,7 @@ gen_lowpart_common (enum machine_mode mode, rtx x)
     }
   else if (GET_CODE (x) == SUBREG || REG_P (x)
 	   || GET_CODE (x) == CONCAT || GET_CODE (x) == CONST_VECTOR
-	   || CONST_DOUBLE_P (x) || CONST_INT_P (x))
+	   || CONST_DOUBLE_AS_FLOAT_P (x) || CONST_SCALAR_INT_P (x))
     return simplify_gen_subreg (mode, x, innermode, offset);
 
   /* Otherwise, we can't do this.  */
diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c
index 0c59b03..50ffaea 100644
--- a/gcc/ira-costs.c
+++ b/gcc/ira-costs.c
@@ -667,7 +667,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
 		  break;
 
 		case 's':
-		  if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op)) 
+		  if (CONST_SCALAR_INT_P (op)) 
 		    break;
 
 		case 'i':
@@ -677,7 +677,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
 		  break;
 
 		case 'n':
-		  if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op)) 
+		  if (CONST_SCALAR_INT_P (op)) 
 		    win = 1;
 		  break;
 
@@ -1068,7 +1068,7 @@ record_address_regs (enum machine_mode mode, addr_space_t as, rtx x,
 
 	/* If the second operand is a constant integer, it doesn't
 	   change what class the first operand must be.  */
-	else if (code1 == CONST_INT || code1 == CONST_DOUBLE)
+	else if (CONST_SCALAR_INT_P (arg1))
 	  record_address_regs (mode, as, arg0, context, PLUS, code1, scale);
 	/* If the second operand is a symbolic constant, the first
 	   operand must be an index register.  */
diff --git a/gcc/ira-lives.c b/gcc/ira-lives.c
index 853832e..a7a2332 100644
--- a/gcc/ira-lives.c
+++ b/gcc/ira-lives.c
@@ -779,22 +779,16 @@ single_reg_class (const char *constraints, rtx op, rtx equiv_const)
 	  break;
 
 	case 'n':
-	  if (CONST_INT_P (op)
-	      || CONST_DOUBLE_AS_INT_P (op)
-	      || (equiv_const != NULL_RTX
-		  && (CONST_INT_P (equiv_const)
-		      || CONST_DOUBLE_AS_INT_P (equiv_const))))
+	  if (CONST_SCALAR_INT_P (op)
+	      || (equiv_const != NULL_RTX && CONST_SCALAR_INT_P (equiv_const)))
 	    return NO_REGS;
 	  break;
 
 	case 's':
-	  if ((CONSTANT_P (op) 
-	       && !CONST_INT_P (op) 
-	       && !CONST_DOUBLE_AS_INT_P (op))
+	  if ((CONSTANT_P (op) && !CONST_SCALAR_INT_P (op))
 	      || (equiv_const != NULL_RTX
 		  && CONSTANT_P (equiv_const)
-		  && !CONST_INT_P (equiv_const)
-		  && !CONST_DOUBLE_AS_INT_P (equiv_const)))
+		  && !CONST_SCALAR_INT_P (equiv_const)))
 	    return NO_REGS;
 	  break;
 
diff --git a/gcc/recog.c b/gcc/recog.c
index f28b021..a53f034 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -586,8 +586,7 @@ simplify_while_replacing (rtx *loc, rtx to, rtx object,
 			 (PLUS, GET_MODE (x), XEXP (x, 0), XEXP (x, 1)), 1);
       break;
     case MINUS:
-      if (CONST_INT_P (XEXP (x, 1))
-	  || CONST_DOUBLE_AS_INT_P (XEXP (x, 1)))
+      if (CONST_SCALAR_INT_P (XEXP (x, 1)))
 	validate_change (object, loc,
 			 simplify_gen_binary
 			 (PLUS, GET_MODE (x), XEXP (x, 0),
@@ -1726,7 +1725,7 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
 	  break;
 
 	case 's':
-	  if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+	  if (CONST_SCALAR_INT_P (op))
 	    break;
 	  /* Fall through.  */
 
@@ -1736,7 +1735,7 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
 	  break;
 
 	case 'n':
-	  if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+	  if (CONST_SCALAR_INT_P (op))
 	    result = 1;
 	  break;
 
@@ -2591,7 +2590,7 @@ constrain_operands (int strict)
 		break;
 
 	      case 's':
-		if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+		if (CONST_SCALAR_INT_P (op))
 		  break;
 	      case 'i':
 		if (CONSTANT_P (op))
@@ -2599,7 +2598,7 @@ constrain_operands (int strict)
 		break;
 
 	      case 'n':
-		if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+		if (CONST_SCALAR_INT_P (op))
 		  win = 1;
 		break;
 
diff --git a/gcc/reload.c b/gcc/reload.c
index 2e41ed6..36197c0 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -3437,7 +3437,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
 		    break;
 
 		  case 's':
-		    if (CONST_INT_P (operand) || CONST_DOUBLE_AS_INT_P (operand))
+		    if (CONST_SCALAR_INT_P (operand))
 		      break;
 		  case 'i':
 		    if (CONSTANT_P (operand)
@@ -3446,7 +3446,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
 		    break;
 
 		  case 'n':
-		    if (CONST_INT_P (operand) || CONST_DOUBLE_AS_INT_P (operand))
+		    if (CONST_SCALAR_INT_P (operand))
 		      win = 1;
 		    break;
 
diff --git a/gcc/rtl.h b/gcc/rtl.h
index cd5d435..8c45e2e 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -430,6 +430,10 @@ struct GTY((variable_size)) rtvec_def {
 #define CONST_DOUBLE_AS_INT_P(X) \
   (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == VOIDmode)
 
+/* Predicate yielding true iff X is an rtx for a integer const.  */
+#define CONST_SCALAR_INT_P(X) \
+  (CONST_INT_P (X) || CONST_DOUBLE_AS_INT_P (X))
+
 /* Predicate yielding true iff X is an rtx for a double-int.  */
 #define CONST_DOUBLE_AS_FLOAT_P(X) \
   (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode)
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index acd4798..933c725 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -729,8 +729,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
 	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
 	{
 	  /* (neg (plus A C)) is simplified to (minus -C A).  */
-	  if (CONST_INT_P (XEXP (op, 1))
-	      || CONST_DOUBLE_P (XEXP (op, 1)))
+	  if (CONST_SCALAR_INT_P (XEXP (op, 1))
+	      || CONST_DOUBLE_AS_FLOAT_P (XEXP (op, 1)))
 	    {
 	      temp = simplify_unary_operation (NEG, mode, XEXP (op, 1), mode);
 	      if (temp)
@@ -1284,7 +1284,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  gcc_assert (GET_MODE_INNER (mode) == GET_MODE_INNER
 						(GET_MODE (op)));
       }
-      if (CONST_INT_P (op) || CONST_DOUBLE_P (op)
+      if (CONST_SCALAR_INT_P (op) || CONST_DOUBLE_AS_FLOAT_P (op)
 	  || GET_CODE (op) == CONST_VECTOR)
 	{
           int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
@@ -1337,7 +1337,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
      check the wrong mode (input vs. output) for a conversion operation,
      such as FIX.  At some point, this should be simplified.  */
 
-  if (code == FLOAT && (CONST_DOUBLE_AS_INT_P (op) || CONST_INT_P (op)))
+  if (code == FLOAT && CONST_SCALAR_INT_P (op))
     {
       HOST_WIDE_INT hv, lv;
       REAL_VALUE_TYPE d;
@@ -1351,8 +1351,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       d = real_value_truncate (mode, d);
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
-  else if (code == UNSIGNED_FLOAT
-	   && (CONST_DOUBLE_AS_INT_P (op) || CONST_INT_P (op)))
+  else if (code == UNSIGNED_FLOAT && CONST_SCALAR_INT_P (op))
     {
       HOST_WIDE_INT hv, lv;
       REAL_VALUE_TYPE d;
@@ -2043,10 +2042,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	}
 
       /* (plus (xor X C1) C2) is (xor X (C1^C2)) if C2 is signbit.  */
-      if ((CONST_INT_P (op1) || CONST_DOUBLE_AS_INT_P (op1))
+      if (CONST_SCALAR_INT_P (op1)
 	  && GET_CODE (op0) == XOR
-	  && (CONST_INT_P (XEXP (op0, 1))
-	      || CONST_DOUBLE_AS_INT_P (XEXP (op0, 1)))
+	  && CONST_SCALAR_INT_P (XEXP (op0, 1))
 	  && mode_signbit_p (mode, op1))
 	return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
 				    simplify_gen_binary (XOR, mode, op1,
@@ -2226,7 +2224,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       /* (-x - c) may be simplified as (-c - x).  */
       if (GET_CODE (op0) == NEG
-	  && (CONST_INT_P (op1) || CONST_DOUBLE_P (op1)))
+	  && (CONST_SCALAR_INT_P (op1) || CONST_DOUBLE_AS_FLOAT_P (op1)))
 	{
 	  tem = simplify_unary_operation (NEG, mode, op1, mode);
 	  if (tem)
@@ -2584,14 +2582,13 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	 return CONST0_RTX (mode);
 
       /* Canonicalize XOR of the most significant bit to PLUS.  */
-      if ((CONST_INT_P (op1) || CONST_DOUBLE_AS_INT_P (op1))
+      if (CONST_SCALAR_INT_P (op1)
 	  && mode_signbit_p (mode, op1))
 	return simplify_gen_binary (PLUS, mode, op0, op1);
       /* (xor (plus X C1) C2) is (xor X (C1^C2)) if C1 is signbit.  */
-      if ((CONST_INT_P (op1) || CONST_DOUBLE_AS_INT_P (op1))
+      if (CONST_SCALAR_INT_P (op1)
 	  && GET_CODE (op0) == PLUS
-	  && (CONST_INT_P (XEXP (op0, 1))
-	      || CONST_DOUBLE_AS_INT_P (XEXP (op0, 1)))
+	  && CONST_SCALAR_INT_P (XEXP (op0, 1))
 	  && mode_signbit_p (mode, XEXP (op0, 1)))
 	return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
 				    simplify_gen_binary (XOR, mode, op1,
@@ -3356,9 +3353,11 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	  gcc_assert (GET_MODE_INNER (mode) == op1_mode);
 
 	if ((GET_CODE (trueop0) == CONST_VECTOR
-	     || CONST_INT_P (trueop0) || CONST_DOUBLE_P (trueop0))
+	     || CONST_SCALAR_INT_P (trueop0) 
+	     || CONST_DOUBLE_AS_FLOAT_P (trueop0))
 	    && (GET_CODE (trueop1) == CONST_VECTOR
-		|| CONST_INT_P (trueop1) || CONST_DOUBLE_P (trueop1)))
+		|| CONST_SCALAR_INT_P (trueop1) 
+		|| CONST_DOUBLE_AS_FLOAT_P (trueop1)))
 	  {
 	    int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
 	    unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
@@ -3455,11 +3454,11 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
   if (VECTOR_MODE_P (mode)
       && code == VEC_CONCAT
-      && (CONST_INT_P (op0)
+      && (CONST_SCALAR_INT_P (op0)
 	  || GET_CODE (op0) == CONST_FIXED
-	  || CONST_DOUBLE_P (op0))
-      && (CONST_INT_P (op1)
-	  || CONST_DOUBLE_P (op1)
+	  || CONST_DOUBLE_AS_FLOAT_P (op0))
+      && (CONST_SCALAR_INT_P (op1)
+	  || CONST_DOUBLE_AS_FLOAT_P (op1)
 	  || GET_CODE (op1) == CONST_FIXED))
     {
       unsigned n_elts = GET_MODE_NUNITS (mode);
@@ -4483,9 +4482,8 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
   /* (eq/ne (xor x C1) C2) simplifies to (eq/ne x (C1^C2)).  */
   if ((code == EQ || code == NE)
       && op0code == XOR
-      && (CONST_INT_P (op1) || CONST_DOUBLE_AS_INT_P (op1))
-      && (CONST_INT_P (XEXP (op0, 1))
-	  || CONST_DOUBLE_AS_INT_P (XEXP (op0, 1))))
+      && CONST_SCALAR_INT_P (op1)
+      && CONST_SCALAR_INT_P (XEXP (op0, 1)))
     return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 0),
 				    simplify_gen_binary (XOR, cmp_mode,
 							 XEXP (op0, 1), op1));
@@ -5502,8 +5500,8 @@ simplify_subreg (enum machine_mode outermode, rtx op,
   if (outermode == innermode && !byte)
     return op;
 
-  if (CONST_INT_P (op)
-      || CONST_DOUBLE_P (op)
+  if (CONST_SCALAR_INT_P (op)
+      || CONST_DOUBLE_AS_FLOAT_P (op)
       || GET_CODE (op) == CONST_FIXED
       || GET_CODE (op) == CONST_VECTOR)
     return simplify_immed_subreg (outermode, op, innermode, byte);

[-- Attachment #3: p3-1.clog --]
[-- Type: text/plain, Size: 846 bytes --]

2012-10-6  Kenneth Zadeck <zadeck@naturalbridge.com>

	* rtl.h (CONST_SCALAR_INT_P): New macro.
   	* cfgexpand.c (expand_debug_locations): Changed to use
	CONST_SCALAR_INT_P macro.
	* combine.c (try_combine, subst, make_extraction,
	gen_lowpart_for_combine): Ditto.
	* cselib.c (entry_and_rtx_equal_p, rtx_equal_for_cselib_1): Ditto.
	* dwarf2out.c (loc_descriptor): Ditto.
	* emit-rtl.c (gen_lowpart_common): Ditto.
	* ira-costs.c (record_reg_classes, record_address_regs): Ditto.
	* ira-lives.c (single_reg_class): Ditto.
	* recog.c (simplify_while_replacing, asm_operand_ok,
	constrain_operands): Ditto.
	* reload.c (find_reloads): Ditto.
	* simplify-rtx.c (simplify_unary_operation_1,
	simplify_const_unary_operation, simplify_binary_operation_1,
	simplify_const_binary_operation, simplify_relational_operation_1,
	simplify_subreg): Ditto.


^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - third small patch
  2012-10-08 11:37                                     ` Kenneth Zadeck
@ 2012-10-08 12:11                                       ` Richard Guenther
  2012-10-08 19:43                                       ` Richard Sandiford
  1 sibling, 0 replies; 217+ messages in thread
From: Richard Guenther @ 2012-10-08 12:11 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, rdsandiford

On Mon, Oct 8, 2012 at 1:36 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> yes, my bad.   here it is with the patches.

Just for the record, ok!

Thanks,
Richard.

> On 10/06/2012 11:55 AM, Kenneth Zadeck wrote:
>>
>> This is the third patch in the series of patches to fix constant math.
>> this one changes some predicates at the rtl level to use the new predicate
>> CONST_SCALAR_INT_P.
>> I did not include a few that were tightly intertwined with other changes.
>>
>> Not all of these changes are strictly mechanical.   Richard, when
>> reviewing this had me make additional changes to remove what he thought were
>> latent bugs at the rtl level.   However, it appears that the bugs were not
>> latent.    I do not know what is going on here but i am smart enough to not
>> look a gift horse in the mouth.
>>
>> All of this was done on the same machine with no changes and identical
>> configs.  It is an x86-64 with ubuntu 12-4.
>>
>> ok for commit?
>>
>> in the logs below, gbBaseline is a trunk from friday and the gbWide is the
>> same revision but with my patches.  Some of this like gfortran.dg/pr32627 is
>> obviously flutter, but the rest does not appear to be.
>>
>> =========
>> heracles:~/gcc(13) gccBaseline/contrib/compare_tests
>> gbBaseline/gcc/testsuite/gcc/gcc.log gbWide/gcc/testsuite/gcc/gcc.log
>> New tests that PASS:
>>
>> gcc.dg/builtins-85.c scan-assembler mysnprintf
>> gcc.dg/builtins-85.c scan-assembler-not __chk_fail
>> gcc.dg/builtins-85.c (test for excess errors)
>>
>>
>> heracles:~/gcc(14) gccBaseline/contrib/compare_tests
>> gbBaseline/gcc/testsuite/gfortran/gfortran.log
>> gbWide/gcc/testsuite/gfortran/gfortran.log
>> New tests that PASS:
>>
>> gfortran.dg/pr32627.f03  -O3 -fomit-frame-pointer -funroll-loops (test for
>> excess errors)
>> gfortran.dg/pr32627.f03  -O3 -fomit-frame-pointer  (test for excess
>> errors)
>> gfortran.dg/pr32627.f03  -Os  (test for excess errors)
>> gfortran.dg/pr32635.f  -O0  execution test
>> gfortran.dg/pr32635.f  -O0  (test for excess errors)
>> gfortran.dg/substr_6.f90  -O2  (test for excess errors)
>>
>> Old tests that passed, that have disappeared: (Eeek!)
>>
>> gfortran.dg/pr32627.f03  -O1  (test for excess errors)
>> gfortran.dg/pr32627.f03  -O3 -fomit-frame-pointer -funroll-all-loops
>> -finline-functions  (test for excess errors)
>> gfortran.dg/pr32627.f03  -O3 -g  (test for excess errors)
>> gfortran.dg/substring_equivalence.f90  -O  (test for excess errors)
>> Using /home/zadeck/gcc/gccBaseline/gcc/testsuite/config/default.exp as
>> tool-and-target-specific interface file.
>>
>>         === g++ Summary ===
>>
>> # of expected passes        49793
>> # of expected failures        284
>> # of unsupported tests        601
>>
>> runtest completed at Fri Oct  5 16:10:20 2012
>> heracles:~/gcc(16) tail gbWide/gcc/testsuite/g++/g++.log Using
>> /usr/share/dejagnu/config/unix.exp as generic interface file for target.
>> Using /home/zadeck/gcc/gccWide/gcc/testsuite/config/default.exp as
>> tool-and-target-specific interface file.
>>
>>         === g++ Summary ===
>>
>> # of expected passes        50472
>> # of expected failures        284
>> # of unsupported tests        613
>>
>> runtest completed at Fri Oct  5 19:51:50 2012
>>
>>
>>
>>
>>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-08  9:27                                     ` Richard Guenther
@ 2012-10-08 15:01                                       ` Nathan Froyd
  2012-10-08 15:11                                         ` Robert Dewar
  2012-10-08 16:18                                         ` Richard Guenther
  0 siblings, 2 replies; 217+ messages in thread
From: Nathan Froyd @ 2012-10-08 15:01 UTC (permalink / raw)
  To: Richard Guenther; +Cc: gcc-patches

----- Original Message -----
> Btw, as for Richards idea of conditionally placing the length field
> in
> rtx_def looks like overkill to me.  These days we'd merely want to
> optimize for 64bit hosts, thus unconditionally adding a 32 bit
> field to rtx_def looks ok to me (you can wrap that inside a union to
> allow both descriptive names and eventual different use - see what
> I've done to tree_base)

IMHO, unconditionally adding that field isn't "optimize for 64-bit
hosts", but "gratuitously make one of the major compiler data
structures bigger on 32-bit hosts".  Not everybody can cross-compile
from a 64-bit host.  And even those people who can don't necessarily
want to.  Please try to consider what's best for all the people who
use GCC, not just the cases you happen to be working with every day.

-Nathan

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-08 15:01                                       ` Nathan Froyd
@ 2012-10-08 15:11                                         ` Robert Dewar
  2012-10-08 19:55                                           ` Richard Sandiford
  2012-10-08 16:18                                         ` Richard Guenther
  1 sibling, 1 reply; 217+ messages in thread
From: Robert Dewar @ 2012-10-08 15:11 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: Richard Guenther, gcc-patches

On 10/8/2012 11:01 AM, Nathan Froyd wrote:
> ----- Original Message -----
>> Btw, as for Richards idea of conditionally placing the length field
>> in
>> rtx_def looks like overkill to me.  These days we'd merely want to
>> optimize for 64bit hosts, thus unconditionally adding a 32 bit
>> field to rtx_def looks ok to me (you can wrap that inside a union to
>> allow both descriptive names and eventual different use - see what
>> I've done to tree_base)
>
> IMHO, unconditionally adding that field isn't "optimize for 64-bit
> hosts", but "gratuitously make one of the major compiler data
> structures bigger on 32-bit hosts".  Not everybody can cross-compile
> from a 64-bit host.  And even those people who can don't necessarily
> want to.  Please try to consider what's best for all the people who
> use GCC, not just the cases you happen to be working with every day.

I think that's rasonable in general, but as time goes on, and every
$300 laptop is 64-bit capable, one should not go TOO far out of the
way trying to make sure we can compile everything on a 32-bit machine.
After all, we don't try to ensure we can compile on a 16-bit machine
though when I helped write the Realia COBOL compiler, it was a major
consideration that we had to be able to compile arbitrarily large
programs on a 32-bit machine with one megabyte of memory. That was
achieved at the time, but is hardly relevant now!

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-08 15:01                                       ` Nathan Froyd
  2012-10-08 15:11                                         ` Robert Dewar
@ 2012-10-08 16:18                                         ` Richard Guenther
  1 sibling, 0 replies; 217+ messages in thread
From: Richard Guenther @ 2012-10-08 16:18 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: gcc-patches

On Mon, Oct 8, 2012 at 5:01 PM, Nathan Froyd <froydnj@mozilla.com> wrote:
> ----- Original Message -----
>> Btw, as for Richards idea of conditionally placing the length field
>> in
>> rtx_def looks like overkill to me.  These days we'd merely want to
>> optimize for 64bit hosts, thus unconditionally adding a 32 bit
>> field to rtx_def looks ok to me (you can wrap that inside a union to
>> allow both descriptive names and eventual different use - see what
>> I've done to tree_base)
>
> IMHO, unconditionally adding that field isn't "optimize for 64-bit
> hosts", but "gratuitously make one of the major compiler data
> structures bigger on 32-bit hosts".  Not everybody can cross-compile
> from a 64-bit host.  And even those people who can don't necessarily
> want to.  Please try to consider what's best for all the people who
> use GCC, not just the cases you happen to be working with every day.

The challenge would of course be to have the overhead only for a minority
of all RTX codes.  After all that 32bits are free to be used for every one.

And I would not consider RTX a 'major compiler data structure' - of course
that makes the whole issue somewhat moot ;)

Richard.

> -Nathan

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch
  2012-10-06  0:14                                 ` patch to fix constant math - first small patch Joseph S. Myers
@ 2012-10-08 19:25                                   ` Kenneth Zadeck
  2012-11-08 17:37                                   ` Kenneth Zadeck
  2013-02-27  0:23                                   ` patch to fix constant math - first small patch - patch ping for the next stage 1 Kenneth Zadeck
  2 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-08 19:25 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Richard Guenther, Mike Stump, gcc-patches, rdsandiford

is this ok to commit with this change?

kenny
On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>
>> +# define HOST_HALF_WIDE_INT_PRINT "h"
> This may cause problems on hosts not supporting %hd (MinGW?), and there's
> no real need for using "h" here given the promotion of short to int; you
> can just use "" (rather than e.g. needing special handling in xm-mingw32.h
> like is done for HOST_LONG_LONG_FORMAT).
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - third small patch
  2012-10-08 11:37                                     ` Kenneth Zadeck
  2012-10-08 12:11                                       ` Richard Guenther
@ 2012-10-08 19:43                                       ` Richard Sandiford
  2012-10-09 15:10                                         ` patch to fix constant math - 4th patch - the wide-int class Kenneth Zadeck
                                                           ` (2 more replies)
  1 sibling, 3 replies; 217+ messages in thread
From: Richard Sandiford @ 2012-10-08 19:43 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Richard Guenther, Mike Stump, gcc-patches

Kenneth Zadeck <zadeck@naturalbridge.com> writes:
> diff --git a/gcc/combine.c b/gcc/combine.c
> index 4e0a579..b531305 100644
> --- a/gcc/combine.c
> +++ b/gcc/combine.c
> @@ -2617,16 +2617,19 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
>       constant.  */
>    if (i1 == 0
>        && (temp = single_set (i2)) != 0
> -      && (CONST_INT_P (SET_SRC (temp))
> -	  || CONST_DOUBLE_AS_INT_P (SET_SRC (temp)))
> +      && CONST_SCALAR_INT_P (SET_SRC (temp))
>        && GET_CODE (PATTERN (i3)) == SET
> -      && (CONST_INT_P (SET_SRC (PATTERN (i3)))
> -	  || CONST_DOUBLE_AS_INT_P (SET_SRC (PATTERN (i3))))
> +      && CONST_SCALAR_INT_P (SET_SRC (PATTERN (i3)))
>        && reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp)))
>      {
>        rtx dest = SET_DEST (PATTERN (i3));
>        int offset = -1;
>        int width = 0;
> +      
> +      /* There are not explicit tests to make sure that this is not a
> +	 float, but there is code here that would not be correct if it
> +	 was.  */
> +      gcc_assert (GET_MODE_CLASS (GET_MODE (SET_SRC (temp))) != MODE_FLOAT);

No need for this assert: CONST_SCALAR_INT_P (SET_SRC (temp)) should cover it.

> @@ -1009,9 +1007,7 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, enum machine_mode memmode)
>  static rtx
>  wrap_constant (enum machine_mode mode, rtx x)
>  {
> -  if (!CONST_INT_P (x) 
> -      && GET_CODE (x) != CONST_FIXED
> -      && !CONST_DOUBLE_AS_INT_P (x))
> +  if ((!CONST_SCALAR_INT_P (x)) && GET_CODE (x) != CONST_FIXED)

Redundant brackets.

Looks good to me otherwise, thanks.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-08 15:11                                         ` Robert Dewar
@ 2012-10-08 19:55                                           ` Richard Sandiford
  2012-10-09  7:09                                             ` Richard Guenther
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2012-10-08 19:55 UTC (permalink / raw)
  To: Robert Dewar; +Cc: Nathan Froyd, Richard Guenther, gcc-patches

Robert Dewar <dewar@adacore.com> writes:
> On 10/8/2012 11:01 AM, Nathan Froyd wrote:
>> ----- Original Message -----
>>> Btw, as for Richards idea of conditionally placing the length field
>>> in
>>> rtx_def looks like overkill to me.  These days we'd merely want to
>>> optimize for 64bit hosts, thus unconditionally adding a 32 bit
>>> field to rtx_def looks ok to me (you can wrap that inside a union to
>>> allow both descriptive names and eventual different use - see what
>>> I've done to tree_base)
>>
>> IMHO, unconditionally adding that field isn't "optimize for 64-bit
>> hosts", but "gratuitously make one of the major compiler data
>> structures bigger on 32-bit hosts".  Not everybody can cross-compile
>> from a 64-bit host.  And even those people who can don't necessarily
>> want to.  Please try to consider what's best for all the people who
>> use GCC, not just the cases you happen to be working with every day.
>
> I think that's rasonable in general, but as time goes on, and every
> $300 laptop is 64-bit capable, one should not go TOO far out of the
> way trying to make sure we can compile everything on a 32-bit machine.

It's not 64-bit machine vs. 32-bit machine.  It's an LP64 ABI vs.
an ILP32 ABI.  HJ & co. have put considerable effort into developing
the x32 ABI for x86_64 precisely because ILP32 is still useful for
64-bit machines.  Just as it was for MIPS when SGI invented n32
(which is still useful now).  I believe 64-bit SPARC has a similar
thing, and no doubt other architectures do too.

After all, there shouldn't be much need for more than 2GB of virtual
address space in an AVR cross compiler.  So why pay the cache penalty
of 64-bit pointers and longs (GCC generally tries to avoid using "long"
directly) when a 32-bit pointer will do?

Many years ago, I moved the HOST_WIDE_INT fields out of rtunion
and into the main rtx_def union because it produced a significant
speed-up on n32 IRIX.  That was before tree-level optimisation,
but I don't think we've really pruned that much RTL optimisation
since then, so I'd be surprised if much has changed.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math
  2012-10-08 19:55                                           ` Richard Sandiford
@ 2012-10-09  7:09                                             ` Richard Guenther
  0 siblings, 0 replies; 217+ messages in thread
From: Richard Guenther @ 2012-10-09  7:09 UTC (permalink / raw)
  To: Robert Dewar, Nathan Froyd, Richard Guenther, gcc-patches, rdsandiford

On Mon, Oct 8, 2012 at 9:55 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Robert Dewar <dewar@adacore.com> writes:
>> On 10/8/2012 11:01 AM, Nathan Froyd wrote:
>>> ----- Original Message -----
>>>> Btw, as for Richards idea of conditionally placing the length field
>>>> in
>>>> rtx_def looks like overkill to me.  These days we'd merely want to
>>>> optimize for 64bit hosts, thus unconditionally adding a 32 bit
>>>> field to rtx_def looks ok to me (you can wrap that inside a union to
>>>> allow both descriptive names and eventual different use - see what
>>>> I've done to tree_base)
>>>
>>> IMHO, unconditionally adding that field isn't "optimize for 64-bit
>>> hosts", but "gratuitously make one of the major compiler data
>>> structures bigger on 32-bit hosts".  Not everybody can cross-compile
>>> from a 64-bit host.  And even those people who can don't necessarily
>>> want to.  Please try to consider what's best for all the people who
>>> use GCC, not just the cases you happen to be working with every day.
>>
>> I think that's rasonable in general, but as time goes on, and every
>> $300 laptop is 64-bit capable, one should not go TOO far out of the
>> way trying to make sure we can compile everything on a 32-bit machine.
>
> It's not 64-bit machine vs. 32-bit machine.  It's an LP64 ABI vs.
> an ILP32 ABI.  HJ & co. have put considerable effort into developing
> the x32 ABI for x86_64 precisely because ILP32 is still useful for
> 64-bit machines.  Just as it was for MIPS when SGI invented n32
> (which is still useful now).  I believe 64-bit SPARC has a similar
> thing, and no doubt other architectures do too.
>
> After all, there shouldn't be much need for more than 2GB of virtual
> address space in an AVR cross compiler.  So why pay the cache penalty
> of 64-bit pointers and longs (GCC generally tries to avoid using "long"
> directly) when a 32-bit pointer will do?
>
> Many years ago, I moved the HOST_WIDE_INT fields out of rtunion
> and into the main rtx_def union because it produced a significant
> speed-up on n32 IRIX.  That was before tree-level optimisation,

But of course that doesn't change the alignment requirement of
that union which is the issue on lp64 hosts.  Also as HOST_WIDE_INT
is 64bits for most ilp32 targets as well it doesn't necessarily save
ilp32 hosts from having this issue (unless long long isn't aligned
to 8 bytes for them).  So what I said is that arranging for the 32bit
hole to contain useful data for most RTXen should be possible.

Richard.

> but I don't think we've really pruned that much RTL optimisation
> since then, so I'd be surprised if much has changed.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-08 19:43                                       ` Richard Sandiford
@ 2012-10-09 15:10                                         ` Kenneth Zadeck
  2012-10-23 14:33                                           ` Richard Biener
  2012-10-09 18:51                                         ` patch to fix constant math - patch 5 - the rest of the rtl stuff Kenneth Zadeck
  2012-11-09 13:22                                         ` patch to fix constant math - third small patch Kenneth Zadeck
  2 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-09 15:10 UTC (permalink / raw)
  To: Richard Guenther, Mike Stump, gcc-patches, rdsandiford

[-- Attachment #1: Type: text/plain, Size: 1122 bytes --]

This patch implements the wide-int class.    this is a more general 
version of the double-int class and is meant to be the eventual 
replacement for that class.    The use of this class removes all 
dependencies of the host from the target compiler's integer math.

I have made all of the changes i agreed to in the earlier emails. In 
particular, this class internally maintains a bitsize and precision but 
not a mode.     The class now is neutral about modes and tree-types.    
the functions that take modes or tree-types are just convenience 
functions that translate the parameters into bitsize and precision and 
where ever there is a call that takes a mode, there is a corresponding 
call that takes a tree-type.

All of the little changes that richi suggested have also been made.

The buffer sizes is now twice the size needed by the largest integer 
mode.     This gives enough room for tree-vrp to do full multiplies on 
any type that the target supports.

Tested on x86-64.

This patch depends on the first three patches.   I am still waiting on 
final approval on the hwint.h patch.

Ok to commit?

kenny



[-- Attachment #2: p4-1.diff --]
[-- Type: text/x-patch, Size: 138935 bytes --]

diff --git a/gcc/wide-int.c b/gcc/wide-int.c
new file mode 100644
index 0000000..bf25467
--- /dev/null
+++ b/gcc/wide-int.c
@@ -0,0 +1,4248 @@
+/* Operations with very long integers.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hwint.h"
+#include "wide-int.h"
+#include "rtl.h"
+#include "tree.h"
+#include "dumpfile.h"
+
+#ifdef DEBUG_WIDE_INT
+  /* Debugging routines.  */
+  static void debug_vw  (const char* name, int r, const wide_int& o0);
+  static void debug_vwh (const char* name, int r, const wide_int &o0,
+			 HOST_WIDE_INT o1);
+  static void debug_vww (const char* name, int r, const wide_int &o0,
+			 const wide_int &o1);
+  static void debug_wv (const char* name, const wide_int &r, int v0);
+  static void debug_wvv (const char* name, const wide_int &r, int v0,
+			 int v1);
+  static void debug_wvvv (const char* name, const wide_int &r, int v0,
+			  int v1, int v2);
+  static void debug_wwv (const char* name, const wide_int &r,
+			 const wide_int &o0, int v0);
+  static void debug_wwwvv (const char* name, const wide_int &r,
+			   const wide_int &o0, const wide_int &o1,
+			   int v0, int v1);
+  static void debug_ww (const char* name, const wide_int &r,
+			const wide_int &o0);
+  static void debug_www (const char* name, const wide_int &r,
+			 const wide_int &o0, const wide_int &o1);
+  static void debug_wwwv (const char* name, const wide_int &r,
+			  const wide_int &o0, const wide_int &o1,
+			  int v0);
+  static void debug_wwww (const char* name, const wide_int &r,
+			  const wide_int &o0, const wide_int &o1, 
+			  const wide_int &o2);
+#endif
+// using wide_int::;
+
+/* Debugging routines.  */
+
+/* This is the maximal size of the buffer needed for dump.  */
+const int MAX = 2 * (MAX_BITSIZE_MODE_ANY_INT / 4
+		     + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
+
+/*
+ * Internal utilities.
+ */
+
+/* Quantities to deal with values that hold half of a wide int.  Used
+   in multiply and divide.  */
+#define HALF_INT_MASK (((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1)
+
+#define BLOCK_OF(TARGET) ((TARGET) / HOST_BITS_PER_WIDE_INT)
+#define BLOCKS_NEEDED(PREC) \
+  (((PREC) + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+
+/*
+ * Conversion routines in and out of wide-int.
+ */
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, unsigned int bitsize, unsigned int precision)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    op0 = sext_hwi (op0, precision);
+
+  result.val[0] = op0;
+  result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+	       "wide_int::from_shwi", result.dump (buf0), op0);
+    }
+#endif
+
+  return result;
+}
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  The overflow bit are set if the number was too
+   large to fit in the mode.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, unsigned int bitsize,
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT t = sext_hwi (op0, precision);
+      if (t != op0)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+  result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+	       "wide_int::from_shwi", result.dump (buf0), op0);
+    }
+#endif
+
+  return result;
+}
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0,
+		     unsigned int bitsize, unsigned int precision)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    op0 = zext_hwi (op0, precision);
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && precision > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+	       "wide_int::from_uhwi", result.dump (buf0), op0);
+    }
+#endif
+
+  return result;
+}
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  The overflow bit are set if the number was too
+   large to fit in the mode.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, unsigned int bitsize, 
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT t = zext_hwi (op0, precision);
+      if (t != op0)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && precision > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+	       "wide_int::from_uhwi", result.dump (buf0), op0);
+    }
+#endif
+
+  return result;
+}
+
+/* Convert a double int into a wide int.  */
+
+wide_int
+wide_int::from_double_int (enum machine_mode mode, double_int di)
+{
+  wide_int result;
+  result.bitsize = GET_MODE_BITSIZE (mode);
+  result.precision = GET_MODE_PRECISION (mode);
+  result.len = 2;
+  result.val[0] = di.low;
+  result.val[1] = di.high;
+  result.canonize ();
+  return result;
+}
+
+/* Convert a integer cst into a wide int.  */
+
+wide_int
+wide_int::from_tree (const_tree tcst)
+{
+#if 1
+  wide_int result;
+  tree type = TREE_TYPE (tcst);
+  unsigned int prec = TYPE_PRECISION (type);
+  HOST_WIDE_INT op = TREE_INT_CST_LOW (tcst);
+
+  result.precision = prec;
+  result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    {
+      if (TYPE_UNSIGNED (type))
+	result.val[0] = zext_hwi (op, prec);
+      else
+	result.val[0] = sext_hwi (op, prec);
+    }
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    {
+	      op = TREE_INT_CST_HIGH (tcst);
+	      if (TYPE_UNSIGNED (type))
+		result.val[1] = zext_hwi (op, prec);
+	      else
+		result.val[1] = sext_hwi (op, prec);
+	    }
+	  else
+	    result.val[1] = TREE_INT_CST_HIGH (tcst);
+	}
+    }
+
+  if (result.len == 2)
+    result.canonize ();
+
+  return result;
+#endif
+  /* This is the code once the tree level is converted.  */
+#if 0
+  wide_int result;
+  int i;
+
+  tree type = TREE_TYPE (tcst);
+
+  result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  result.precision = TYPE_PRECISION (type);
+  result.len = TREE_INT_CST_LEN (tcst);
+  for (i = 0; i < result.len; i++)
+    result.val[i] = TREE_INT_CST_ELT (tcst, i);
+
+  return result;
+#endif
+}
+
+/* Extract a constant integer from the X of type MODE.  The bits of
+   the integer are returned.  */
+
+wide_int
+wide_int::from_rtx (const_rtx x, enum machine_mode mode)
+{
+  wide_int result;
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  gcc_assert (mode != VOIDmode);
+
+  result.bitsize = GET_MODE_BITSIZE (mode);
+  result.precision = prec;
+
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+      if ((prec & (HOST_BITS_PER_WIDE_INT - 1)) != 0)
+	result.val[0] = sext_hwi (INTVAL (x), prec);
+      else
+	result.val[0] = INTVAL (x);
+      result.len = 1;
+      break;
+
+#if TARGET_SUPPORTS_WIDE_INT
+    case CONST_WIDE_INT:
+      {
+	int i;
+	result.len = CONST_WIDE_INT_NUNITS (x);
+	
+	for (i = 0; i < result.len; i++)
+	  result.val[i] = CONST_WIDE_INT_ELT (x, i);
+      }
+      break;
+#else
+    case CONST_DOUBLE:
+      result.len = 2;
+      result.val[0] = CONST_DOUBLE_LOW (x);
+      result.val[1] = CONST_DOUBLE_HIGH (x);
+      result.canonize ();
+      break;
+#endif
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return result;
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = sext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS is too large for
+   the mode's precision, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi () const
+{
+  return to_shwi (precision);
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = zext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS is too large for
+   the mode's precision, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi () const
+{
+  return to_uhwi (precision);
+}
+
+/*
+ * Largest and smallest values in a mode.
+ */
+
+/* Produce the largest number that is represented in BITSIZE of
+   PREC. SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (unsigned int bitsize, unsigned int prec, SignOp sgn)
+{
+  wide_int result;
+  
+  result.bitsize = bitsize;
+  result.precision = prec;
+
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned max is just all ones, for which the compressed
+	 rep is just a single HWI.  */ 
+      result.len = 1;
+      result.val[0] = (HOST_WIDE_INT)-1;
+    }
+  else
+    {
+      /* The signed max is all ones except the top bit.  This must be
+	 explicitly represented.  */
+      int i;
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      int shift = (small_prec == 0) 
+	? HOST_BITS_PER_WIDE_INT - 1 : small_prec - 1;
+
+      result.len = BLOCKS_NEEDED (prec);
+      for (i = 0; i < result.len - 1; i++)
+	result.val[i] = (HOST_WIDE_INT)-1;
+
+      result.val[result.len - 1] = ((HOST_WIDE_INT)1 << shift) - 1;
+    }
+  
+  return result;
+}
+
+/* Produce the largest number that is represented in MODE. The
+   bitsize and precision are taken from mode.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (enum machine_mode mode, SignOp sgn)
+{
+  return max_value (GET_MODE_BITSIZE (mode), GET_MODE_PRECISION (mode), sgn);
+}
+
+/* Produce the largest number that is represented in TYPE. The
+   bitsize and precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::max_value (const_tree type)
+{
+  return max_value (GET_MODE_BITSIZE (TYPE_MODE (type)), 
+		    TYPE_PRECISION (type), 
+		    TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+/* Produce the smallest number that is represented in BITSIZE of
+   PREC. SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::min_value (unsigned int bitsize, unsigned int prec, SignOp sgn)
+{
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned min is just all zeros, for which the compressed
+	 rep is just a single HWI.  */ 
+      wide_int result;
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = prec;
+      result.val[0] = 0;
+      return result;
+    }
+  else
+    {
+      /* The signed min is all zeros except the top bit.  This must be
+	 explicitly represented.  */
+      return set_bit_in_zero (prec - 1, bitsize, prec);
+    }
+}
+
+/* Produce the smallest number that is represented in MODE. The
+   bitsize and precision are taken from mode.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::min_value (enum machine_mode mode, SignOp sgn)
+{
+  return min_value (GET_MODE_BITSIZE (mode), GET_MODE_PRECISION (mode), sgn);
+}
+
+/* Produce the smallest number that is represented in TYPE. The
+   bitsize and precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::min_value (const_tree type)
+{
+  return min_value (GET_MODE_BITSIZE (TYPE_MODE (type)), 
+		    TYPE_PRECISION (type), 
+		    TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+/*
+ * Public utilities.
+ */
+
+/* Check the upper HOST_WIDE_INTs of src to see if the length can be
+   shortened.  An upper HOST_WIDE_INT is unnecessary if it is all ones
+   or zeros and the top bit of the next lower word matches.
+
+   This function may change the representation of THIS, but does not
+   change the value that THIS represents.  It does not sign extend in
+   the case that the size of the mode is less than
+   HOST_BITS_PER_WIDE_INT.  */
+
+void
+wide_int::canonize ()
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT top;
+  int i;
+
+  if (len > blocks_needed)
+    len = blocks_needed;
+
+  /* Clean up the top bits for any mode that is not a multiple of a HWI.  */
+  if (len == blocks_needed && small_prec)
+    val[len - 1] = sext_hwi (val[len - 1], small_prec);
+
+  if (len == 1)
+    return;
+
+  top = val[len - 1];
+  if (top != 0 && top != (HOST_WIDE_INT)-1)
+    return;
+
+  /* At this point we know that the top is either 0 or -1.  Find the
+     first block that is not a copy of this.  */
+  for (i = len - 2; i >= 0; i--)
+    {
+      HOST_WIDE_INT x = val[i];
+      if (x != top)
+	{
+	  if (x >> (HOST_BITS_PER_WIDE_INT - 1) == top)
+	    {
+	      len = i + 1;
+	      return;
+	    }
+
+	  /* We need an extra block because the top bit block i does
+	     not match the extension.  */
+	  len = i + 2;
+	  return;
+	}
+    }
+
+  /* The number is 0 or -1.  */
+  len = 1;
+}
+
+/* Copy THIS replacing the mode with MODE.  */
+
+wide_int
+wide_int::force_to_size (unsigned int bs, unsigned int prec) const
+{
+  wide_int result;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (prec);
+  int i;
+
+  result.bitsize = bs;
+  result.precision = prec;
+  result.len = blocks_needed < len ? blocks_needed : len;
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+
+  if (small_prec & (blocks_needed == len))
+    result.val[blocks_needed-1]
+      = sext_hwi (result.val[blocks_needed-1], small_prec);
+  return result;
+}
+
+/*
+ * public printing routines.
+ */
+
+/* Try to print the signed self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_DEC, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decs (buf);
+  fputs (buf, file);
+}
+
+/* Try to print the unsigned self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decu (buf);
+  fputs (buf, file);
+}
+
+void 
+wide_int::print_hex (char *buf) const
+{
+  int i = len;
+
+  if (zero_p ())
+    sprintf (buf, "0x");
+  else
+    {
+      if (neg_p ())
+	{
+	  int j;
+	  /* If the number is negative, we may need to pad value with
+	     0xFFF...  because the leading elements may be missing and
+	     we do not print a '-' with hex.  */
+	  for (j = BLOCKS_NEEDED (precision); j > i; j--)
+	    buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, (HOST_WIDE_INT) -1);
+	    
+	}
+      else
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_HEX, val [--i]);
+      while (-- i >= 0)
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, val [i]);
+    }
+}
+
+/* Print one big hex number to FILE.  Note that some assemblers may not
+   accept this for large modes.  */
+void 
+wide_int::print_hex (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_hex (buf);
+  fputs (buf, file);
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently singed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+bool
+wide_int::operator == (const wide_int &op1) const
+{
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool result;
+
+  if (this == &op1)
+    {
+      result = true;
+      goto ex;
+    }
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << precision) - 1;
+      result = (val[0] & mask) == (op1.val[0] & mask);
+      goto ex;
+    }
+
+  while (l0 > l1)
+    if (val[l0--] != op1.sign_mask ())
+      {
+	result = false;
+	goto ex;
+      }
+
+  while (l1 > l0)
+    if (op1.val[l1--] != sign_mask ())
+      {
+	result = false;
+	goto ex;
+      }
+
+  while (l0 >= 0)
+    if (val[l0--] != op1.val[l1--])
+      {
+	result = false;
+	goto ex;
+      }
+
+  result = true;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("operator ==", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS > OP1 using signed comparisons.  */
+
+bool
+wide_int::gts_p (const HOST_WIDE_INT op1) const
+{
+  bool result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] > sext_hwi (op1, precision);
+      goto ex;
+    }
+  
+  result = !neg_p ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int::gts_p", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS > OP1 using unsigned comparisons.  */
+
+bool
+wide_int::gtu_p (const unsigned HOST_WIDE_INT op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  if (precision < HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1, precision);
+
+      result = x0 > x1;
+    }
+  else
+    result = true;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int::gtu_p", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p (const HOST_WIDE_INT op1) const
+{
+  bool result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] < sext_hwi (op1, precision);
+      goto ex;
+    }
+  
+  result = neg_p ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int::lts_p", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p (const wide_int &op1) const
+{
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool result;
+
+  if (this == &op1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] < op1.val[0];
+      goto ex;
+    }
+
+  while (l0 > l1)
+    if (val[l0--] < op1.sign_mask ())
+      {
+	result = true;
+	goto ex;
+      }
+
+  while (l1 > l0)
+    if (sign_mask () < op1.val[l1--])
+      {
+	result = true;
+	goto ex;
+      }
+
+  while (l0 >= 0)
+    if (val[l0--] < op1.val[l1--])
+      {
+	result = true;
+	goto ex;
+      }
+
+  result = false;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int::lts_p", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p (const unsigned HOST_WIDE_INT op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  if (precision < HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1, precision);
+
+      result = x0 < x1;
+    }
+  else
+    result = false;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int::ltu_p", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool result;
+
+  if (this == &op1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1.val[0], precision);
+
+      result = x0 < x1;
+      goto ex;
+    }
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1.sign_mask ();
+      if (x0 < x1)
+	{
+	  result = true;
+	  goto ex;
+	}
+    }
+
+  while (l1 > l0)
+    {
+      x0 = sign_mask ();
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	{
+	  result = true;
+	  goto ex;
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	{
+	  result = true;
+	  goto ex;
+	}
+    }
+
+  result = false;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int::ltu_p", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p (unsigned int prec) const
+{
+  int i;
+  HOST_WIDE_INT x;
+  int small_prec;
+  bool result;
+
+  if (BLOCKS_NEEDED (prec) != len)
+    {
+      result = false;
+      goto ex;
+    }
+
+  for (i=0; i < len - 1; i++)
+    if (val[i] != 0)
+      {
+	result = false;
+	goto ex;
+      }
+
+  x = val[len - 1];
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec)
+    x = x << (HOST_BITS_PER_WIDE_INT - small_prec);
+
+  result = x == ((HOST_WIDE_INT)1) << (HOST_BITS_PER_WIDE_INT - 1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int::only_sign_bit_p", result, *this);
+#endif
+
+  return result;
+}
+
+bool
+wide_int::only_sign_bit_p () const
+{
+  return only_sign_bit_p (precision);
+}
+
+/* Returns true if THIS fits into range of TYPE.  Signedness of OP0 is
+   assumed to be the same as the signedness of TYPE.  */
+
+bool
+wide_int::fits_to_tree_p (const_tree type) const
+{
+  int type_prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return fits_u_p (type_prec);
+  else
+    return fits_s_p (type_prec);
+}
+
+/* Returns true of THIS fits in the unsigned range of precision.  */
+
+bool
+wide_int::fits_s_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == sext (prec);
+}
+
+
+/* Returns true if THIS fits into range of TYPE.  */
+
+bool
+wide_int::fits_u_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == zext (prec);
+}
+
+/*
+ * Extension.
+ */
+
+/* Sign extend THIS starting at OFFSET within the precision of the mode.  */
+
+wide_int
+wide_int::sext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+
+  gcc_assert (precision >= offset);
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[0] = sext_hwi (val[0], offset);
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::sext", result, *this, offset);
+#endif
+
+      return result;
+    }
+
+  if (precision == offset)
+    {
+      result = force_to_size (bitsize, precision);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::sext", result, *this, offset);
+#endif
+      return result;
+    }
+
+  result = decompress (offset, bitsize, precision);
+
+  /* Now we can do the real sign extension.  */
+  off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  if (off)
+    {
+      int block = BLOCK_OF (offset);
+      result.val[block] = sext_hwi (val[block], off);
+      result.len = block + 1;
+    }
+  /* We never need an extra element for sign extended values.  */
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::sext", result, *this, offset);
+#endif
+
+  return result;
+}
+
+/* Sign extend THIS to mode M.  */
+
+wide_int
+wide_int::sext (enum machine_mode m) const
+{
+  /* Assuming that MODE is larger than THIS, the compressed value of
+     op0 and the result will be the same.  The only thing that is
+     different is that the mode of the result will be different.  */
+  return force_to_size (GET_MODE_BITSIZE (m), GET_MODE_PRECISION (m));
+}
+
+/* Zero extend THIS starting at OFFSET within the precision of the mode.  */
+
+wide_int
+wide_int::zext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+  int block;
+
+  gcc_assert (precision >= offset);
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[0] = zext_hwi (val[0], offset);
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::zext", result, *this, offset);
+#endif
+
+      return result;
+    }
+
+  if (precision == offset)
+    {
+      result = force_to_size (bitsize, precision);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::zext", result, *this, offset);
+#endif
+      return result;
+    }
+
+  result = decompress (offset, bitsize, precision);
+
+  /* Now we can do the real zero extension.  */
+  off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  block = BLOCK_OF (offset);
+  if (off)
+    {
+      result.val[block] = zext_hwi (val[block], off);
+      result.len = block + 1;
+    }
+  else
+    /* See if we need an extra zero element to satisfy the compression
+       rule.  */
+    if (val[block - 1] < 0 && offset < precision)
+      {
+	result.val[block] = 0;
+	result.len += 1;
+      }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::zext", result, *this, offset);
+#endif
+
+  return result;
+}
+
+/* Zero extend THIS to mode M.  */
+
+wide_int
+wide_int::zext (enum machine_mode m) const
+{
+  wide_int result;
+  int off;
+  int block;
+  unsigned int res_bitsize = GET_MODE_BITSIZE (m);
+  unsigned int res_prec = GET_MODE_PRECISION (m);
+
+  gcc_assert (res_prec >= precision);
+
+  if (res_prec < HOST_BITS_PER_WIDE_INT)
+    {
+      result.bitsize = res_bitsize;
+      result.precision = res_prec;
+      result.val[0] = zext_hwi (val[0], precision);
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::zext", result, *this, res_prec);
+#endif
+      return result;
+    }
+
+  result = decompress (precision, res_bitsize, res_prec);
+
+  /* Now we can do the real zero extension.  */
+  off = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  block = BLOCK_OF (precision);
+  if (off)
+    {
+      result.val[block] = zext_hwi (val[block], off);
+      result.len = block + 1;
+    }
+  else
+    /* See if we need an extra zero element to satisfy the compression
+       rule.  */
+    if (val[block - 1] < 0 && precision < res_prec)
+      {
+	result.val[block] = 0;
+	result.len += 1;
+      }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::zext", result, *this, res_prec);
+#endif
+
+  return result;
+}
+
+/*
+ * Masking, inserting, shifting, rotating.
+ */
+
+/* Return a value with a one bit inserted in THIS at BITPOS.  */
+
+wide_int
+wide_int::set_bit (unsigned int bitpos) const
+{
+  wide_int result;
+  int i, j;
+
+  if (bitpos >= precision)
+    result = force_to_size (bitsize, precision);
+  else
+    {
+      result = decompress (bitpos, bitsize, precision);
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::set_bit", result, *this, bitpos);
+#endif
+
+  return result;
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with BITSIZE
+   and PRECISION.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, 
+			   unsigned int bitsize, unsigned int prec)
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (bitpos);
+  int i, j;
+
+  result.bitsize = bitsize;
+  result.precision = prec;
+  if (bitpos >= prec)
+    {
+      result.len = 1;
+      result.val[0] = 0;
+    }
+  else
+    {
+      result.len = blocks_needed;
+      for (i = 0; i < blocks_needed; i++)
+	result.val[i] = 0;
+      
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wv ("wide_int::set_bit_in_zero", result, bitpos);
+#endif
+
+  return result;
+}
+
+/* Insert WIDTH bits from OP0 into THIS starting at START.  */
+
+wide_int
+wide_int::insert (const wide_int &op0, unsigned int start, 
+		  unsigned int width) const
+{
+  wide_int result;
+  wide_int mask;
+  wide_int tmp;
+
+  if (start + width >= precision) 
+    width = precision - start;
+
+  mask = shifted_mask (start, width, false, bitsize, precision);
+  tmp = op0.lshift (start, NONE, bitsize, precision);
+  result = tmp & mask;
+
+  tmp = and_not (mask);
+  result = result | tmp;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwwvv ("wide_int::insert", result, *this, op0, start, width);
+#endif
+
+  return result;
+}
+
+/* bswap THIS.  */
+
+wide_int
+wide_int::bswap () const
+{
+  wide_int result;
+  int i, s;
+  int end;
+  int len = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT mask = sign_mask ();
+
+  /* This is not a well defined operation if the precision is not a
+     multiple of 8.  */
+  gcc_assert ((precision & 0x7) == 0);
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < len; i++)
+    result.val[0] = mask;
+
+  /* Only swap the bytes that are not the padding.  */
+  if ((precision & (HOST_BITS_PER_WIDE_INT - 1))
+      && (this->len == len))
+    end = precision;
+  else
+    end = this->len * HOST_BITS_PER_WIDE_INT;
+
+  for (s = 0; s < end; s += 8)
+    {
+      unsigned int d = precision - s - 8;
+      unsigned HOST_WIDE_INT byte;
+
+      int block = s / HOST_BITS_PER_WIDE_INT;
+      int offset = s & (HOST_BITS_PER_WIDE_INT - 1);
+
+      byte = (val[block] >> offset) & 0xff;
+
+      block = d / HOST_BITS_PER_WIDE_INT;
+      offset = d & (HOST_BITS_PER_WIDE_INT - 1);
+
+      result.val[block] &= ((((HOST_WIDE_INT)1 << offset) + 8)
+			    - ((HOST_WIDE_INT)1 << offset));
+      result.val[block] |= byte << offset;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int::bswap", result, *this);
+#endif
+
+  return result;
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with BITSIZE and
+   PREC. */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, 
+		unsigned int bitsize, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  int shift;
+
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (bitsize, prec);
+      else
+	result = wide_int::zero (bitsize, prec);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wvv ("wide_int::mask", result, width, negate);
+#endif
+      return result;
+    }
+
+  result.bitsize = bitsize;
+  result.precision = prec;
+
+  while (i < width / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = width & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      HOST_WIDE_INT last = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~last : last;
+    }
+  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvv ("wide_int::mask", result, width, negate);
+#endif
+
+  return result;
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  */
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate,
+			unsigned int bitsize, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  unsigned int shift;
+  unsigned int end = start + width;
+  HOST_WIDE_INT block;
+
+  if (start + width > prec)
+    width = prec - start;
+ 
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (bitsize, prec);
+      else
+	result = wide_int::zero (bitsize, prec);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wvv ("wide_int::shifted_mask", result, width, negate);
+#endif
+      return result;
+    }
+
+  result.bitsize = bitsize;
+  result.precision = prec;
+
+  while (i < start / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? (HOST_WIDE_INT)-1 : 0;
+
+  shift = start & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift)
+    {
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      shift = (end) & (HOST_BITS_PER_WIDE_INT - 1);
+      if (shift)
+	{
+	  /* case 000111000 */
+	  block = (((HOST_WIDE_INT)1) << shift) - block - 1;
+	  result.val[i++] = negate ? ~block : block;
+	  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_wvvv ("wide_int::shifted_mask", result, start,
+			width, negate);
+#endif
+	  return result;
+	}
+      else
+	/* ...111000 */
+	result.val[i++] = negate ? block : ~block;
+    }
+
+  while (i < end / HOST_BITS_PER_WIDE_INT)
+    /* 1111111 */
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = end & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      /* 000011111 */
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~block : block;
+    }
+
+  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvvv ("wide_int::shifted_mask", result, start, width,
+		negate);
+#endif
+
+  return result;
+}
+
+
+/*
+ * logical operations.
+ */
+
+/* Return THIS & OP1.  */
+
+wide_int
+wide_int::operator & (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = len > op1.len ? len : op1.len;
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	  result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l0] = op1.val[l0];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator &", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Return THIS & ~OP1.  */
+
+wide_int
+wide_int::and_not (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = len > op1.len ? len : op1.len;
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l0] = ~op1.val[l0];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & ~op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::and_not", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+wide_int
+wide_int::operator | (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = len > op1.len ? len : op1.len;
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l0] = op1.val[l0];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator |", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Return the logical negation (bitwise complement) of THIS.  */
+
+wide_int
+wide_int::operator ~ () const
+{
+  wide_int result;
+  int l0 = len - 1;
+
+  result.len = len;
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = ~val[l0];
+      l0--;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int::operator ~", result, *this);
+#endif
+  return result;
+}
+
+/* Return THIS | ~OP1.  */
+
+wide_int
+wide_int::or_not (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = len > op1.len ? len : op1.len;
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l0] = ~op1.val[l0];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | ~op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::and_not", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Return the exclusive ior (xor) of THIS and OP1.  */
+
+wide_int
+wide_int::operator ^ (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  result.len = len > op1.len ? len : op1.len;
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  while (l0 > l1)
+    {
+      result.val[l0] = val[l0] ^ op1.sign_mask ();
+      l0--;
+    }
+
+  while (l1 > l0)
+    {
+      result.val[l0] = sign_mask () ^ op1.val[l0];
+      l1--;
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] ^ op1.val[l0];
+      l0--;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator ^", result, *this, op1);
+#endif
+  return result;
+}
+
+/*
+ * math
+ */
+
+/* Absolute value of THIS.  */
+
+wide_int
+wide_int::abs () const
+{
+  if (sign_mask ())
+    return neg ();
+
+  wide_int result = force_to_size (bitsize, precision);
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int::abs", result, *this);
+#endif
+  return result;
+}
+
+/* Add of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::operator + (const wide_int &op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec, stop;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      o1 = op1.val[0];
+      result.val[0] = sext_hwi (o0 + o1, precision);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator +", result, *this, op1);
+#endif
+      return result;
+    }
+
+  stop = len > op1.len ? len : op1.len;
+  /* Need to do one extra block just to handle the special cases.  */
+  if (stop < (unsigned)BLOCKS_NEEDED (precision))
+    stop++;
+
+  result.len = stop;
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < stop; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1.len ? (unsigned HOST_WIDE_INT)op1.val[i] : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator +", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Add of THIS and signed OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::operator + (HOST_WIDE_INT op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec, stop;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      result.val[0] = sext_hwi (o0 + op1, precision);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::add", result, *this, op1);
+#endif
+      return result;
+    }
+
+  stop = len;
+  /* Need to do one extra block just to handle the special cases.  */
+  if (stop < (unsigned)BLOCKS_NEEDED (precision))
+    stop++;
+
+  result.len = stop;
+  mask0 = sign_mask ();
+  mask1 = op1 >> (HOST_BITS_PER_WIDE_INT - 1);
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < 1 ? (unsigned HOST_WIDE_INT)op1 : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator +", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Add of THIS and unsigned OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::operator + (unsigned HOST_WIDE_INT op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0;
+  unsigned int i, small_prec, stop;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      result.val[0] = sext_hwi (o0 + op1, precision);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator +", result, *this, op1);
+#endif
+      return result;
+    }
+
+  stop = len;
+  /* Need to do one extra block just to handle the special cases.  */
+  if (stop < (unsigned)BLOCKS_NEEDED (precision))
+    stop++;
+
+  result.len = stop;
+  mask0 = sign_mask ();
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < stop; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < 1 ? (unsigned HOST_WIDE_INT)op1 : 0;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator +", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Add of OP0 and OP1 with overflow checking.  If the result overflows
+   within the precision, set OVERFLOW.  OVERFLOW is assumed to be
+   sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::add_overflow (const wide_int *op0, const wide_int *op1,
+			wide_int::SignOp sgn, bool *overflow)
+{
+  wide_int result;
+  const wide_int *tmp;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned int prec = op0->precision;
+  int i, small_prec;
+
+  result.precision = op0->precision;
+  result.bitsize = op0->bitsize;
+
+  /* Put the longer one first.  */
+  if (op0->len > op1->len)
+    {
+      tmp = op0;
+      op0 = op1;
+      op1 = tmp;
+    }
+
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < op0->len; i++)
+    {
+      o0 = op0->val[i];
+      o1 = op1->val[i];
+      x = o0 + o1 + carry;
+      result.elt_ref (i) = x;
+      carry = x < o0;
+    }
+
+  /* Uncompress the rest.  */
+  if (op0->len < op1->len)
+    {
+      unsigned HOST_WIDE_INT mask = op1->sign_mask ();
+      for (i = op0->len; i < op1->len; i++)
+	{
+	  o0 = op0->val[i];
+	  o1 = mask;
+	  x = o0 + o1 + carry;
+	  result.val[i] = x;
+	  carry = x < o0;
+	}
+    }
+
+  result.set_len (op0->len);
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (op0->len * HOST_BITS_PER_WIDE_INT < prec)
+	{
+	  /* If the carry is 1, then we need another word.  If the carry
+	     is 0, we only need another word if the top bit is 1.  */
+	  if (carry == 1
+	      || (x >> (HOST_BITS_PER_WIDE_INT - 1) == 1))
+	    /* Check for signed overflow.  */
+	    {
+	      result.val[result.len] = carry;
+	      result.len++;
+	    }
+	  if (sgn == wide_int::SIGNED)
+	    {
+	      if (((x ^ o0) & (x ^ o1)) >> (HOST_BITS_PER_WIDE_INT - 1))
+		*overflow = true;
+	    }
+	  else if (carry)
+	    {
+	      if ((~o0) < o1)
+		*overflow = true;
+	    }
+	  else
+	    {
+	      if ((~o0) <= o1)
+		*overflow = true;
+	    }
+	}
+    }
+  else
+    {
+      /* Overflow in this case is easy since we can see bits beyond
+	 the precision.  If the value computed is not the sign
+	 extended value, then we have overflow.  */
+      unsigned HOST_WIDE_INT y;
+
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  Then the rest of the code just works.  */
+	  o0 = zext_hwi (o0, small_prec);
+	  o1 = zext_hwi (o1, small_prec);
+	  x = o0 + o1 + carry;
+	}
+      /* Short integers and modes with weird precisions.  */
+      y = sext_hwi (x, small_prec);
+      result.len = op1->len;
+      if (BLOCKS_NEEDED (prec) == result.len && x != y)
+	*overflow = true;
+      /* Then put the sign extended form back because that is the
+	 canonical form.  */
+      result.val[result.len - 1] = y;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::add_overflow", result, *op0, *op1);
+#endif
+  return result;
+}
+
+/* Add this and X.  If overflow occurs, set OVERFLOW.  */
+
+wide_int
+wide_int::add (const wide_int &x, SignOp sgn, bool *overflow) const
+{
+  return add_overflow (this, &x, sgn, overflow);
+}
+
+/* Count leading zeros of THIS but only looking at the bits in the
+   smallest HWI of size mode.  */
+
+wide_int
+wide_int::clz (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (clz (), bs, prec);
+}
+
+/* Count leading zeros of THIS.  */
+
+int
+wide_int::clz () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_vw ("wide_int::clz", count, *this);
+#endif
+      return count;
+    }
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = clz_hwi (v) - (HOST_BITS_PER_WIDE_INT - small_prec);
+      start = len - 2;
+      if (v != 0)
+	{
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_vw ("wide_int::clz", count, *this);
+#endif
+	  return count;
+	}
+    }
+  else
+    {
+      count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = elt (i);
+      count += clz_hwi (v);
+      if (v != 0)
+	break;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int::clz", count, *this);
+#endif
+  return count;
+}
+
+wide_int
+wide_int::clrsb (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (clrsb (), bs, prec);
+}
+
+/* Count the number of redundant leading bits of THIS.  Return result
+   as a HOST_WIDE_INT.  There is a wrapper to convert this into a
+   wide_int.  */
+
+int
+wide_int::clrsb () const
+{
+  if (neg_p ())
+    return operator ~ ().clz () - 1;
+
+  return clz () - 1;
+}
+
+wide_int
+wide_int::ctz (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (ctz (), bs, prec);
+}
+
+/* Count zeros of THIS.  Return result as a HOST_WIDE_INT.  There is a
+   wrapper to convert this into a wide_int.  */
+
+int
+wide_int::ctz () const
+{
+  int i;
+  unsigned int count = 0;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int end;
+  bool more_to_do;
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_vw ("wide_int::ctz", count, *this);
+#endif
+      return count;
+    }
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      end = len - 1;
+      more_to_do = true;
+    }
+  else
+    {
+      end = len;
+      more_to_do = false;
+    }
+
+  for (i = 0; i < end; i++)
+    {
+      v = val[i];
+      count += ctz_hwi (v);
+      if (v != 0)
+	{
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_vw ("wide_int::ctz", count, *this);
+#endif
+	  return count;
+	}
+    }
+
+  if (more_to_do)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = ctz_hwi (v);
+      /* The top word was all zeros so we have to cut it back to prec,
+	 because we are counting some of the zeros above the
+	 interesting part.  */
+      if (count > precision)
+	count = precision;
+    }
+  else
+    /* Skip over the blocks that are not represented.  They must be
+       all zeros at this point.  */
+    count = precision;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int::ctz", count, *this);
+#endif
+  return count;
+}
+
+/* ffs of THIS.  */
+
+wide_int
+wide_int::ffs () const
+{
+  HOST_WIDE_INT count = ctz ();
+  if (count == precision)
+    count = 0;
+  else
+    count += 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int::ffs", count, *this);
+#endif
+  return wide_int::from_shwi (count, word_mode);
+}
+
+/* Subroutines of the multiplication and division operations.  Unpack
+   the first IN_LEN HOST_WIDE_INTs in INPUT into 2 * IN_LEN
+   HOST_HALF_WID_INTs of RESULT.  The rest of RESULT is filled by
+   uncompressing the top bit of INPUT[IN_LEN - 1].  */
+
+static void
+wi_unpack (unsigned HOST_HALF_WIDE_INT *result, 
+	   const unsigned HOST_WIDE_INT *input,
+	   int in_len, int out_len)
+{
+  int i;
+  int j = 0;
+  HOST_WIDE_INT mask;
+
+  for (i = 0; i <in_len; i++)
+    {
+      result[j++] = input[i];
+      result[j++] = input[i] >> HOST_BITS_PER_HALF_WIDE_INT;
+    }
+  mask = ((HOST_WIDE_INT)input[in_len - 1]) >> (HOST_BITS_PER_WIDE_INT - 1);
+  mask &= HALF_INT_MASK;
+
+  /* Smear the sign bit.  */
+  while (j < out_len)
+    result[j++] = mask;
+}
+
+/* The inverse of wi_unpack.  */
+
+static void
+wi_pack (unsigned HOST_WIDE_INT *result, 
+	 const unsigned HOST_HALF_WIDE_INT *input, 
+	 int in_len)
+{
+  int i = 0;
+  int j = 0;
+
+  while (i < in_len)
+    {
+      result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+	| ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+      i += 2;
+    }
+}
+
+/* Return an integer that is the exact log2 of THIS.  */
+
+int
+wide_int::exact_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  HOST_WIDE_INT count;
+  HOST_WIDE_INT result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec < HOST_BITS_PER_WIDE_INT)
+	v = sext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = ::exact_log2 (v);
+      goto ex;
+    }
+
+  count = ctz ();
+  if (clz () + count + 1 == precision)
+    {
+      result = count;
+      goto ex;
+    }
+
+  result = -1;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int::exact_log2", result, *this);
+#endif
+  return result;
+}
+
+/* Multiply Op1 by Op2.  If HIGH is set, only the upper half of the
+   result is returned.  If FULL is set, the entire result is returned
+   in a mode that is twice the width of the inputs.  However, that
+   mode needs to exist if the value is to be usable.  Clients that use
+   FULL need to check for this.
+
+   If HIGH or FULL are not setm throw away the upper half after the check
+   is made to see if it overflows.  Unfortunately there is no better
+   way to check for overflow than to do this.  OVERFLOW is assumed to
+   be sticky so it should be initialized.  SGN controls the signess
+   and is used to check overflow or if HIGH or FULL is set.  */
+
+static wide_int
+mul_internal (bool high, bool full, 
+			const wide_int *op1, const wide_int *op2,
+			wide_int::SignOp sgn,  bool *overflow, bool needs_overflow)
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1, k, t;
+  unsigned int i;
+  unsigned int j;
+  unsigned int prec = op1->get_precision ();
+  unsigned int blocks_needed = 2 * BLOCKS_NEEDED (prec);
+  unsigned HOST_HALF_WIDE_INT u[2 * MAX_BITSIZE_MODE_ANY_INT
+			   / HOST_BITS_PER_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT v[2 * MAX_BITSIZE_MODE_ANY_INT
+			   / HOST_BITS_PER_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT r[4 * MAX_BITSIZE_MODE_ANY_INT
+			   / HOST_BITS_PER_WIDE_INT];
+  HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT / 2)) - 1;
+
+  result.set_bitsize (op1->get_bitsize ());
+  result.set_precision (op1->get_precision ());
+
+  if (high || full || needs_overflow)
+    {
+      /* If we need to check for overflow, we can only do half wide
+	 multiplies quickly because we need to look at the top bits to
+	 check for the overflow.  */
+      if (prec <= HOST_BITS_PER_HALF_WIDE_INT)
+	{
+	  HOST_WIDE_INT t;
+	  result.set_len (1);
+	  o0 = op1->elt (0);
+	  o1 = op2->elt (0);
+	  t = o0 * o1;
+	  /* Signed shift down will leave 0 or -1 if there was no
+	     overflow for signed or 0 for unsigned.  */
+	  t = t >> (HOST_BITS_PER_HALF_WIDE_INT - 1);
+	  if (needs_overflow)
+	    {
+	      if (sgn == wide_int::SIGNED)
+		{
+		  if (t != (HOST_WIDE_INT)-1 && t != 0)
+		    *overflow = true;
+		}
+	      else
+		{
+		  if (t != 0)
+		    *overflow = true;
+		}
+	    }
+	  if (full)
+	    {
+	      result.elt_ref (0) = sext_hwi (t, prec << 1);
+	      result.set_bitsize (op1->get_bitsize () * 2);
+	      result.set_precision (op1->get_precision () * 2);
+	    }
+	  else if (high)
+	    result.elt_ref (0) = sext_hwi (t >> (prec >> 1), prec);
+	  else
+	    result.elt_ref (0) = sext_hwi (t, prec);
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_www ("wide_int::mul_overflow", result, *op1, *op2);
+#endif
+	  return result;
+	}
+    }
+  else
+    {
+      if (prec <= HOST_BITS_PER_WIDE_INT)
+	{
+	  result.set_len (1);
+	  o0 = op1->elt (0);
+	  o1 = op2->elt (0);
+	  result.elt_ref (0) = sext_hwi (o0 * o1, prec);
+	  
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_www ("wide_int::mul_overflow", result, *op1, *op2);
+#endif
+	  return result;
+	}
+    }
+
+  wi_unpack (u, &op1->uelt_ref (0), op1->get_len (), blocks_needed);
+  wi_unpack (v, &op2->uelt_ref (0), op2->get_len (), blocks_needed);
+
+  memset (r, 0, blocks_needed * 2 * HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT);
+
+  for (j = 0; j < blocks_needed; j++)
+    {
+      k = 0;
+      for (i = 0; i < blocks_needed; i++)
+	{
+	  t = ((unsigned HOST_WIDE_INT)u[i] * (unsigned HOST_WIDE_INT)v[j]
+	       + r[i + j] + k);
+	  r[i + j] = t & HALF_INT_MASK;
+	  k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	}
+      r[j + blocks_needed] = k;
+    }
+
+  if (needs_overflow)
+    {
+      HOST_WIDE_INT top;
+
+      /* For unsigned, overflow is true if any of the top bits are set.
+	 For signed, overflow is true if any of the top bits are not equal
+	 to the sign bit.  */
+      if (sgn == wide_int::UNSIGNED)
+	top = 0;
+      else
+	{
+	  top = r[blocks_needed - 1];
+	  top = ((top << (HOST_BITS_PER_WIDE_INT / 2))
+		 >> (HOST_BITS_PER_WIDE_INT - 1));
+	  top &= mask;
+	}
+      
+      for (i = blocks_needed; i < 2 * blocks_needed; i++)
+	if (((HOST_WIDE_INT)(r[i] & mask)) != top)
+	  *overflow = true; 
+    }
+
+  if (full)
+    {
+      /* compute [2prec] <- [prec] * [prec] */
+      wi_pack (&result.uelt_ref (0), r, blocks_needed);
+      result.set_len (blocks_needed);
+      result.set_bitsize (op1->get_bitsize () * 2);
+      result.set_precision (op1->get_precision () * 2);
+    }
+  else if (high)
+    {
+      /* compute [prec] <- ([prec] * [prec]) >> [prec] */
+      wi_pack (&result.uelt_ref (blocks_needed >> 1), r, blocks_needed >> 1);
+      result.set_len (blocks_needed / 2);
+    }
+  else
+    {
+      /* compute [prec] <- ([prec] * [prec]) && ((1 << [prec]) - 1) */
+      wi_pack (&result.uelt_ref (0), r, blocks_needed >> 1);
+      result.set_len (blocks_needed / 2);
+    }
+      
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwwv ("wide_int::mul_overflow", result, *op1, *op2, *overflow);
+#endif
+  return result;
+}
+
+/* Multiply THIS and OP1.  The result is the same precision as the
+   operands, so there is no reason for signed or unsigned
+   versions.  */
+
+wide_int
+wide_int::operator * (const wide_int &op1) const
+{
+  bool overflow;
+
+  return mul_internal (false, false, this, &op1, UNSIGNED, &overflow, false);
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.
+   OVERFLOW is set true if the result overflows.  */
+
+wide_int 
+wide_int::mul (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  return mul_internal (false, false, this, &op1, sgn, overflow, true);
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.  The
+   result is twice the precision as the operands.  The signess is
+   specified with SGN.  */
+
+wide_int
+wide_int::mul_full (const wide_int &op1, SignOp sgn) const
+{
+  bool overflow;
+
+  return mul_internal (false, true, this, &op1, sgn, &overflow, false);
+}
+
+/* Multiply THIS and OP1 and return the high part of that result.  The
+   signess is specified with SGN.  The result is the same precision as
+   the operands.  The mode is the same mode as the operands.  The
+   signess is specified with y.  */
+
+wide_int
+wide_int::mul_high (const wide_int &op1, SignOp sgn) const
+{
+  bool overflow;
+
+  return mul_internal (true, false, this, &op1, sgn, &overflow, false);
+}
+
+/* Negate THIS.  */
+
+wide_int
+wide_int::neg () const
+{
+  wide_int z = wide_int::from_shwi (0, bitsize, precision);
+  return z - *this;
+}
+
+/* Compute the parity of THIS.  */
+
+wide_int
+wide_int::parity (unsigned int bs, unsigned int prec) const
+{
+  int count = popcount ();
+  return wide_int::from_shwi (count & 1, bs, prec);
+}
+
+/* Compute the population count of THIS producing a number with
+   BITSIZE and PREC.  */
+
+wide_int
+wide_int::popcount (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (popcount (), bs, prec);
+}
+
+/* Compute the population count of THIS.  */
+
+int
+wide_int::popcount () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = popcount_hwi (v);
+      start = len - 2;
+    }
+  else
+    {
+      if (sign_mask ())
+	count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      else
+	count = 0;
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = val[i];
+      count += popcount_hwi (v);
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int::popcount", count, *this);
+#endif
+  return count;
+}
+
+/* Subtract of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::operator - (const wide_int &op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the carry in of the first element at 1.  */
+  unsigned HOST_WIDE_INT carry = 1;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec, stop;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      o1 = op1.val[0];
+      result.val[0] = sext_hwi (o0 - o1, precision);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator -", result, *this, op1);
+#endif
+      return result;
+    }
+
+  stop = len > op1.len ? len : op1.len;
+  /* Need to do one extra block just to handle the special cases.  */
+  if (stop < (unsigned)BLOCKS_NEEDED (precision))
+    stop++;
+
+  result.len = stop;
+  mask0 = sign_mask ();
+  mask1 = ~op1.sign_mask ();
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < stop; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1.len ? (unsigned HOST_WIDE_INT)~op1.val[i] : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::operator -", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Subtract of signed OP1 from THIS.  No overflow is detected.  */
+
+wide_int
+wide_int::operator - (HOST_WIDE_INT op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the carry in of the first element at 1.  */
+  unsigned HOST_WIDE_INT carry = 1;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec, stop;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      result.val[0] = sext_hwi (o0 - op1, precision);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator -", result, *this, op1);
+#endif
+      return result;
+    }
+
+  stop = len;
+  /* Need to do one extra block just to handle the special cases.  */
+  if (stop < (unsigned)BLOCKS_NEEDED (precision))
+    stop++;
+
+  result.len = stop;
+  mask0 = sign_mask ();
+  mask1 = ~(op1 >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < stop; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < 1 ? (unsigned HOST_WIDE_INT)~op1 : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator -", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Subtract of unsigned OP1 from THIS.  No overflow is detected.  */
+
+wide_int
+wide_int::operator - (unsigned HOST_WIDE_INT op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the carry in of the first element at 1.  */
+  unsigned HOST_WIDE_INT carry = 1;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec, stop;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+ 
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      result.val[0] = sext_hwi (o0 - op1, precision);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator -", result, *this, op1);
+#endif
+      return result;
+    }
+
+  stop = len;
+  /* Need to do one extra block just to handle the special cases.  */
+  if (stop < (unsigned)BLOCKS_NEEDED (precision))
+    stop++;
+
+  result.len = stop;
+  mask0 = sign_mask ();
+  mask1 = (HOST_WIDE_INT) -1;
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < stop; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < 1 ? (unsigned HOST_WIDE_INT)~op1 : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::operator -", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Subtract of THIS and OP1 with overflow checking.  If the result
+   overflows within the precision, set OVERFLOW.  OVERFLOW is assumed
+   to be sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::sub_overflow (const wide_int *op0, const wide_int *op1, 
+			wide_int::SignOp sgn, bool *overflow)
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the carry in of the first element at 1.  */
+  unsigned HOST_WIDE_INT carry = 1;
+  int i, small_prec;
+
+  result.bitsize = op0->bitsize;
+  result.precision = op0->precision;
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < op0->len; i++)
+    {
+      o0 = op0->val[i];
+      o1 = ~op1->val[i];
+      x = o0 + o1 + carry;
+      result.elt_ref (i) = x;
+      carry = x < o0;
+    }
+
+  /* Uncompress the rest.  */
+  if (op1->len < op1->len)
+    {
+      unsigned HOST_WIDE_INT mask = op1->sign_mask ();
+      for (i = op0->len; i < op1->len; i++)
+	{
+	  o0 = op0->val[i];
+	  o1 = ~mask;
+	  x = o0 + o1 + carry;
+	  result.elt_ref (i) = x;
+	  carry = x < o0;
+	}
+    }
+  else if (op0->len > op1->len)
+    {
+      unsigned HOST_WIDE_INT mask = op1->sign_mask ();
+      for (i = op0->len; i < op1->len; i++)
+	{
+	  o0 = mask;
+	  o1 = ~op1->val[i];
+	  x = o0 + o1 + carry;
+	  result.val[i] = x;
+	  carry = x < o0;
+	}
+    }
+
+  result.set_len (op0->len);
+  small_prec = op0->precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (op0->len * HOST_BITS_PER_WIDE_INT < op0->precision)
+	{
+	  /* If the carry is 1, then we need another word.  If the carry
+	     is 0, we only need another word if the top bit is 1.  */
+	  if (carry == 1
+	      || (x >> (HOST_BITS_PER_WIDE_INT - 1) == 1))
+	    {
+	      /* Check for signed overflow.  */
+	      result.val[result.len] = carry;
+	      result.len++;
+	    }
+	  if (sgn == wide_int::SIGNED)
+	    {
+	      if (((x ^ o0) & (x ^ o1)) >> (HOST_BITS_PER_WIDE_INT - 1))
+		*overflow = true;
+	    }
+	  else if (carry)
+	    {
+	      if ((~o0) < o1)
+		*overflow = true;
+	    }
+	  else
+	    {
+	      if ((~o0) <= o1)
+		*overflow = true;
+	    }
+	}
+    }
+  else
+    {
+      /* Overflow in this case is easy since we can see bits beyond
+	 the precision.  If the value computed is not the sign
+	 extended value, then we have overflow.  */
+      unsigned HOST_WIDE_INT y;
+
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  Then the rest of the code just works.  */
+	  o0 = zext_hwi (o0, small_prec);
+	  o1 = zext_hwi (o1, small_prec);
+	  x = o0 + o1 + carry;
+	}
+      /* Short integers and modes with weird precisions.  */
+      y = sext_hwi (x, small_prec);
+      result.len =  op1->len;
+      if (BLOCKS_NEEDED (op1->precision) == result.len && x != y)
+	*overflow = true;
+      /* Then put the sign extended form back because that is the
+	 canonical form.  */
+      result.val[result.len - 1] = y;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int::sub_overflow", result, *op0, *op1);
+#endif
+  return result;
+}
+
+/* sub X from THIS.  If overflow occurs, set OVERFLOW.  */
+
+wide_int
+wide_int::sub (const wide_int &x, SignOp sgn, bool *overflow) const
+{
+  return sub_overflow (this, &x, sgn, overflow);
+}
+
+/*
+ * Division and Mod
+ */
+
+/* Compute B_QUOTIENT and B_REMAINDER from B_DIVIDEND/B_DIVISOR.  The
+   algorithm is a small modification of the algorithm in Hacker's
+   Delight by Warren, which itself is a small modification of Knuth's
+   algorithm.  M is the number of significant elements of U however
+   there needs to be at least one extra element of B_DIVIDEND
+   allocated, N is the number of elements of B_DIVISOR.  */
+
+static void
+divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+		   unsigned HOST_HALF_WIDE_INT *b_remainder,
+		   unsigned HOST_HALF_WIDE_INT *b_dividend, 
+		   unsigned HOST_HALF_WIDE_INT *b_divisor, 
+		   int m, int n)
+{
+  /* The "digits" are a HOST_HALF_WIDE_INT which the size of half of a
+     HOST_WIDE_INT and stored in the lower bits of each word.  This
+     algorithm should work properly on both 32 and 64 bit
+     machines.  */
+  unsigned HOST_WIDE_INT b
+    = (unsigned HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT;
+  unsigned HOST_WIDE_INT qhat;   /* Estimate of quotient digit.  */
+  unsigned HOST_WIDE_INT rhat;   /* A remainder.  */
+  unsigned HOST_WIDE_INT p;      /* Product of two digits.  */
+  HOST_WIDE_INT s, i, j, t, k;
+
+  /* Single digit divisor.  */
+  if (n == 1)
+    {
+      k = 0;
+      for (j = m - 1; j >= 0; j--)
+	{
+	  b_quotient[j] = (k * b + b_dividend[j])/b_divisor[0];
+	  k = ((k * b + b_dividend[j])
+	       - ((unsigned HOST_WIDE_INT)b_quotient[j]
+		  * (unsigned HOST_WIDE_INT)b_divisor[0]));
+	}
+      b_remainder[0] = k;
+      return;
+    }
+
+  s = clz_hwi (b_divisor[n-1]) - HOST_BITS_PER_HALF_WIDE_INT; /* CHECK clz */
+
+  /* Normalize B_DIVIDEND and B_DIVISOR.  Unlike the published
+     algorithm, we can overwrite b_dividend and b_divisor, so we do
+     that.  */
+  for (i = n - 1; i > 0; i--)
+    b_divisor[i] = (b_divisor[i] << s)
+      | (b_divisor[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_divisor[0] = b_divisor[0] << s;
+
+  b_dividend[m] = b_dividend[m-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s);
+  for (i = m - 1; i > 0; i--)
+    b_dividend[i] = (b_dividend[i] << s)
+      | (b_dividend[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_dividend[0] = b_dividend[0] << s;
+
+  /* Main loop.  */
+  for (j = m - n; j >= 0; j--)
+    {
+      qhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) / b_divisor[n-1];
+      rhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) - qhat * b_divisor[n-1];
+    again:
+      if (qhat >= b || qhat * b_divisor[n-2] > b * rhat + b_dividend[j+n-2])
+	{
+	  qhat -= 1;
+	  rhat += b_divisor[n-1];
+	  if (rhat < b)
+	    goto again;
+	}
+
+      /* Multiply and subtract.  */
+      k = 0;
+      for (i = 0; i < n; i++)
+	{
+	  p = qhat * b_divisor[i];
+	  t = b_dividend[i+j] - k - (p & HALF_INT_MASK);
+	  b_dividend[i + j] = t;
+	  k = ((p >> HOST_BITS_PER_HALF_WIDE_INT)
+	       - (t >> HOST_BITS_PER_HALF_WIDE_INT));
+	}
+      t = b_dividend[j+n] - k;
+      b_dividend[j+n] = t;
+
+      b_quotient[j] = qhat;
+      if (t < 0)
+	{
+	  b_quotient[j] -= 1;
+	  k = 0;
+	  for (i = 0; i < n; i++)
+	    {
+	      t = (HOST_WIDE_INT)b_dividend[i+j] + b_divisor[i] + k;
+	      b_dividend[i+j] = t;
+	      k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	    }
+	  b_dividend[j+n] += k;
+	}
+    }
+  for (i = 0; i < n; i++)
+    b_remainder[i] = (b_dividend[i] >> s) 
+      | (b_dividend[i+1] << (HOST_BITS_PER_HALF_WIDE_INT - s));
+}
+
+
+/* Do a truncating divide DIVISOR into DIVIDEND.  The result is the
+   same size as the operands.  SIGN is either wide_int::SIGNED or
+   wide_int::UNSIGNED.  */
+
+static wide_int
+divmod_internal (bool compute_quotient, 
+		 const wide_int *dividend, const wide_int *divisor,
+		 wide_int::SignOp sgn, wide_int *remainder,
+		 bool compute_remainder, 
+		 bool *overflow)
+{
+  wide_int quotient, u0, u1;
+  unsigned int prec = dividend->get_precision();
+  unsigned int bs = dividend->get_bitsize ();
+  int blocks_needed = 2 * BLOCKS_NEEDED (prec);
+  unsigned HOST_HALF_WIDE_INT b_quotient[2 * MAX_BITSIZE_MODE_ANY_INT
+				/ HOST_BITS_PER_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT b_remainder[2 * MAX_BITSIZE_MODE_ANY_INT
+				/ HOST_BITS_PER_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT b_dividend[(2 * MAX_BITSIZE_MODE_ANY_INT
+				 / HOST_BITS_PER_WIDE_INT) + 1];
+  unsigned HOST_HALF_WIDE_INT b_divisor[2 * MAX_BITSIZE_MODE_ANY_INT
+				/ HOST_BITS_PER_WIDE_INT];
+  int m, n;
+  bool dividend_neg = false;
+  bool divisor_neg = false;
+
+  if ((*divisor).zero_p ())
+    *overflow = true;
+
+  /* The smallest signed number / -1 causes overflow.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      wide_int t = wide_int::set_bit_in_zero (prec - 1, 
+					      bs, 
+					      prec);
+      if (*dividend == t && (*divisor).minus_one_p ())
+	*overflow = true;
+    }
+
+  quotient.set_bitsize (bs);
+  remainder->set_bitsize (bs);
+  quotient.set_precision (prec);
+  remainder->set_precision (prec);
+
+  /* If overflow is set, just get out.  There will only be grief by
+     continuing.  */
+  if (*overflow)
+    {
+      if (compute_remainder)
+	{
+	  remainder->set_len (1);
+	  remainder->elt_ref (0) = 0;
+	}
+      return wide_int::zero (bs, prec);
+    }
+
+  /* Do it on the host if you can.  */
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      quotient.set_len (1);
+      remainder->set_len (1);
+      if (sgn == wide_int::SIGNED)
+	{
+	  quotient.elt_ref (0) 
+	    = sext_hwi (dividend->elt (0) / divisor->elt (0), prec);
+	  remainder->elt_ref (0) 
+	    = sext_hwi (dividend->elt (0) % divisor->elt (0), prec);
+	}
+      else
+	{
+	  unsigned HOST_WIDE_INT o0 = dividend->elt (0);
+	  unsigned HOST_WIDE_INT o1 = divisor->elt (0);
+
+	  if (prec < HOST_BITS_PER_WIDE_INT)
+	    {
+	      o0 = zext_hwi (o0, prec);
+	      o1 = zext_hwi (o1, prec);
+	    }
+	  quotient.elt_ref (0) = sext_hwi (o0 / o1, prec);
+	  remainder->elt_ref (0) = sext_hwi (o0 % o1, prec);
+	}
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwww ("wide_int::divmod", quotient, *remainder, *dividend, *divisor);
+#endif
+      return quotient;
+    }
+
+  /* Make the divisor and divident positive and remember what we
+     did.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      if (dividend->sign_mask ())
+	{
+	  u0 = dividend->neg ();
+	  dividend = &u0;
+	  dividend_neg = true;
+	}
+      if (divisor->sign_mask ())
+	{
+	  u1 = divisor->neg ();
+	  divisor = &u1;
+	  divisor_neg = true;
+	}
+    }
+
+  wi_unpack (b_dividend, &dividend->uelt_ref (0), dividend->get_len (),
+	     blocks_needed);
+  wi_unpack (b_divisor, &divisor->uelt_ref (0), divisor->get_len (),
+	     blocks_needed);
+
+  if (dividend->sign_mask ())
+    m = blocks_needed;
+  else
+    m = 2 * dividend->get_len ();
+
+  if (divisor->sign_mask ())
+    n = blocks_needed;
+  else
+    n = 2 * divisor->get_len ();
+
+  divmod_internal_2 (b_quotient, b_remainder, b_dividend, b_divisor, m, n);
+
+  if (compute_quotient)
+    {
+      wi_pack (&quotient.uelt_ref (0), b_quotient, m);
+      quotient.set_len (m / 2);
+      quotient.canonize ();
+      /* The quotient is neg if exactly one of the divisor or dividend is
+	 neg.  */
+      if (dividend_neg != divisor_neg)
+	quotient = quotient.neg ();
+    }
+
+  if (compute_remainder)
+    {
+      wi_pack (&remainder->uelt_ref (0), b_remainder, n);
+      remainder->set_len (n / 2);
+      (*remainder).canonize ();
+      /* The remainder is always the same sign as the dividend.  */
+      if (dividend_neg)
+	*remainder = (*remainder).neg ();
+    }
+
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwww ("wide_int::divmod", quotient, *remainder, *dividend, *divisor);
+#endif
+  return quotient;
+}
+
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is
+   truncated.  */
+
+wide_int
+wide_int::div_trunc (const wide_int &divisor, SignOp sgn) const
+{
+  wide_int remainder;
+  bool overflow;
+
+  return divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, false, &overflow);
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is truncated.
+   Overflow is set to true if the result overflows, otherwise it is
+   not set.  */
+wide_int
+wide_int::div_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  
+  return divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, false, overflow);
+}
+
+/* Divide DIVISOR into THIS producing both the quotient and remainder.
+   The result is the same size as the operands.  The sign is specified
+   in SGN.  The output is truncated.  */
+
+wide_int
+wide_int::divmod_trunc (const wide_int &divisor, wide_int *remainder, SignOp sgn) const
+{
+  bool overflow;
+
+  return divmod_internal (true, this, &divisor, sgn, 
+			  remainder, true, &overflow);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  */
+
+wide_int
+wide_int::mod_trunc (const wide_int &divisor, SignOp sgn) const
+{
+  bool overflow;
+  wide_int remainder;
+
+  divmod_internal (false, this, &divisor, sgn, 
+		   &remainder, true, &overflow);
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+
+  divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, true, overflow);
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is floor
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return quotient - (HOST_WIDE_INT)1;
+  return quotient;
+}
+
+
+/* Divide DIVISOR into THIS.  The remainder is also produced in
+   REMAINDER.  The result is the same size as the operands.  The sign
+   is specified in SGN.  The output is floor truncated.  Overflow is
+   set to true if the result overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::divmod_floor (const wide_int &divisor, wide_int *remainder, SignOp sgn) const
+{
+  wide_int quotient;
+  bool overflow;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      remainder, true, &overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !(*remainder).zero_p ())
+    {
+      *remainder = *remainder - divisor;
+      return quotient - (HOST_WIDE_INT)1;
+    }
+  return quotient;
+}
+
+
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is floor truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return remainder - divisor;
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is ceil
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return quotient;
+      else
+	return quotient + (HOST_WIDE_INT)1;
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is the
+   same size as the operands.  The sign is specified in SGN.  The
+   output is ceil truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return remainder;
+      else
+	return remainder - divisor;
+    }
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is round
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_round (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+  if (!remainder.zero_p ())
+    {
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return quotient - (HOST_WIDE_INT)1;
+	      else 
+		return quotient + (HOST_WIDE_INT)1;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return quotient + (unsigned HOST_WIDE_INT)1;
+	}
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is round truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_round (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return remainder + divisor;
+	      else 
+		return remainder - divisor;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return remainder - divisor;
+	}
+    }
+  return remainder;
+}
+
+/*
+ * Shifting, rotating and extraction.
+ */
+
+/* If SHIFT_COUNT_TRUNCATED is defined, truncate CNT.   
+
+   At first look, the shift truncation code does not look right.
+   Shifts (and rotates) are done according to the precision of the
+   mode but the shift count is truncated according to the bitsize
+   of the mode.   This is how real hardware works.
+
+   On an ideal machine, like Knuth's mix machine, a shift count is a
+   word long and all of the bits of that word are examined to compute
+   the shift amount.  But on real hardware, especially on machines
+   with fast (single cycle shifts) that takes too long.  On these
+   machines, the amount of time to perform a shift dictates the cycle
+   time of the machine so corners are cut to keep this fast.  A
+   comparison of an entire 64 bit word would take something like 6
+   gate delays before the shifting can even start.
+
+   So real hardware only looks at a small part of the shift amount.
+   On ibm machines, this tends to be 1 more than what is necessary to
+   encode the shift amount.  The rest of the world looks at only the
+   minimum number of bits.  This means that only 3 gate delays are
+   necessary to set up the shifter.
+
+   On the other hand, right shifts and rotates must be according to
+   the precision or the operation does not make any sense.   */
+static inline int
+trunc_shift (unsigned int bitsize, int cnt)
+{
+#ifdef SHIFT_COUNT_TRUNCATED
+  cnt = cnt & (bitsize - 1);
+#endif
+  return cnt;
+}
+
+/* This function is called in two contexts.  If OP == TRUNC, this
+   function provides a count that matches the semantics of the target
+   machine depending on the value of SHIFT_COUNT_TRUNCATED.  Note that
+   if SHIFT_COUNT_TRUNCATED is not defined, this function may produce
+   -1 as a value if the shift amount is greater than the bitsize of
+   the mode.  -1 is a surrogate for a very large amount.
+
+   If OP == NONE, then this function always truncates the shift value
+   to the bitsize because this shifting operation is a function that
+   is internal to GCC.  */
+
+static inline int
+trunc_shift (unsigned int bitsize, const wide_int *cnt, wide_int::ShiftOp z)
+{
+  if (z == wide_int::TRUNC)
+    {
+#ifdef SHIFT_COUNT_TRUNCATED
+      return cnt->elt (0) & (bitsize - 1);
+#else
+      if (cnt.ltu (bitsize))
+	return cnt->elt (0) & (bitsize - 1);
+      else 
+	return -1;
+#endif
+    }
+  else
+    return cnt->elt (0) & (bitsize - 1);
+}
+
+/* Extract WIDTH bits from THIS starting at OFFSET.  The result is
+   assumed to fit in a HOST_WIDE_INT.  This function is safe in that
+   it can properly access elements that may not be explicitly
+   represented.  */
+
+HOST_WIDE_INT
+wide_int::extract_to_hwi (int offset, int width) const
+{
+  int start_elt, end_elt, shift;
+  HOST_WIDE_INT x;
+
+  /* Get rid of the easy cases first.   */
+  if (offset >= len * HOST_BITS_PER_WIDE_INT)
+    return sign_mask ();
+  if (offset + width <= 0)
+    return 0;
+
+  shift = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset < 0)
+    {
+      start_elt = -1;
+      end_elt = 0;
+      x = 0;
+    }
+  else
+    {
+      start_elt = offset / HOST_BITS_PER_WIDE_INT;
+      end_elt = (offset + width - 1) / HOST_BITS_PER_WIDE_INT;
+      x = start_elt >= len ? sign_mask () : val[start_elt] >> shift;
+    }
+
+  if (start_elt != end_elt)
+    {
+      HOST_WIDE_INT y = end_elt == len
+	? sign_mask () : val[end_elt];
+
+      x = (unsigned HOST_WIDE_INT)x >> shift;
+      x |= y << (HOST_BITS_PER_WIDE_INT - shift);
+    }
+
+  if (width != HOST_BITS_PER_WIDE_INT)
+    x &= ((HOST_WIDE_INT)1 << width) - 1;
+
+  return x;
+}
+
+
+/* Left shift by an integer Y.  See the definition of Op.TRUNC for how
+   to set Z.  */
+
+wide_int
+wide_int::lshift (unsigned int y, ShiftOp z) const
+{
+  return lshift (y, z, bitsize, precision);
+}
+
+/* Left shifting by an wide_int shift amount.  See the definition of
+   Op.TRUNC for how to set Z.  */
+
+wide_int
+wide_int::lshift (const wide_int &y, ShiftOp z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (bitsize, &y, TRUNC);
+      if (shift == -1)
+	return wide_int::zero (bitsize, precision);
+      return lshift (shift, NONE, bitsize, precision);
+    }
+  else
+    return lshift (trunc_shift (bitsize, &y, NONE), NONE, bitsize, precision);
+}
+
+/* Left shift THIS by CNT.  See the definition of Op.TRUNC for how to
+   set Z.  Since this is used internally, it has the ability to
+   specify the BISIZE and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+wide_int
+wide_int::lshift (unsigned int cnt, ShiftOp op, 
+		  unsigned int bs, unsigned int res_prec) const
+{
+  wide_int result;
+  unsigned int i;
+
+  result.bitsize = bs;
+  result.precision = res_prec;
+
+  if (op == TRUNC)
+    cnt = trunc_shift (bs, cnt);
+
+  /* Handle the simple case quickly.   */
+  if (res_prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[0] = val[0] << cnt;
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::lshift", result, *this, cnt);
+#endif
+
+      return result;
+    }
+
+  if (cnt >= res_prec)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::lshift", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  for (i = 0; i < res_prec; i += HOST_BITS_PER_WIDE_INT)
+    result.val[i / HOST_BITS_PER_WIDE_INT]
+      = extract_to_hwi (i - cnt, HOST_BITS_PER_WIDE_INT);
+
+  result.len = BLOCKS_NEEDED (res_prec);
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::lshift", result, *this, cnt);
+#endif
+
+  return result;
+}
+
+/* Rotate THIS left by Y within its precision.  */
+
+wide_int
+wide_int::lrotate (const wide_int &y) const
+{
+  return lrotate (y.extract_to_hwi (0, HOST_BITS_PER_WIDE_INT));
+}
+
+/* Rotate THIS left by CNT within its precision.  */
+
+wide_int
+wide_int::lrotate (unsigned int cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (cnt, NONE);
+  right = rshiftu (precision - cnt, NONE);
+  result = left | right;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::lrotate", result, *this, cnt);
+#endif
+  return result;
+}
+
+/* Unsigned right shift by Y.  See the definition of Op.TRUNC for how
+   to set Z.  */
+
+wide_int
+wide_int::rshiftu (const wide_int &y, ShiftOp z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (bitsize, &y, TRUNC);
+      if (shift == -1)
+	return wide_int::zero (bitsize, precision);
+      return rshiftu (shift, NONE);
+    }
+  else
+    return rshiftu (trunc_shift (bitsize, &y, NONE), NONE);
+}
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set Z.  */
+
+wide_int
+wide_int::rshiftu (unsigned int cnt, ShiftOp trunc_op) const
+{
+  wide_int result;
+  int stop_block, offset, i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (trunc_op == TRUNC)
+    cnt = trunc_shift (bitsize, cnt);
+
+  if (cnt == 0)
+    {
+      result = force_to_size (bitsize, precision);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::rshiftu", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  /* Handle the simple case quickly.   */
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT x = val[0];
+
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	x = zext_hwi (x, precision);
+
+      result.val[0] = x >> cnt;
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::rshiftu", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  if (cnt >= precision)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::rshiftu", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  offset = (precision - cnt) & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset)
+    result.val[stop_block - 1] = zext_hwi (result.val[stop_block - 1], offset);
+  else
+    /* The top block had a 1 at the top position so it will decompress
+       wrong unless a zero block is added.  This only works because we
+       know the shift was greater than 0.  */
+    if (result.val[stop_block - 1] < 0)
+      result.val[result.len++] = 0;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:rshiftu", result, *this, cnt);
+#endif
+  return result;
+}
+
+/* Signed right shift by Y.  See the definition of Op.TRUNC for how to
+   set Z.  */
+wide_int
+wide_int::rshifts (const wide_int &y, ShiftOp z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (bitsize, &y, TRUNC);
+      if (shift == -1)
+	{
+	  /* The value of the shift was larger than the bitsize and this
+	     machine does not truncate the value, so the result is
+	     a smeared sign bit.  */
+	  if (neg_p ())
+	    return wide_int::minus_one (bitsize, precision);
+	  else
+	    return wide_int::zero (bitsize, precision);
+	}
+      return rshifts (shift, NONE);
+    }
+  else
+    return rshifts (trunc_shift (bitsize, &y, NONE), NONE);
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set Z.  */
+
+wide_int
+wide_int::rshifts (unsigned int cnt, ShiftOp trunc_op) const
+{
+  wide_int result;
+  int stop_block, i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (trunc_op == TRUNC)
+    cnt = trunc_shift (bitsize, cnt);
+
+  if (cnt == 0)
+    {
+      result = force_to_size (bitsize, precision);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::rshifts", result, *this, cnt);
+#endif
+      return result;
+    }
+  /* Handle the simple case quickly.   */
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT x = val[0];
+      result.val[0] = x >> cnt;
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::rshifts", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  if (cnt >= precision)
+    {
+      HOST_WIDE_INT m = sign_mask ();
+      result.val[0] = m;
+      result.len = 1;
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int::rshifts", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  /* No need to sign extend the last block, since it extract_to_hwi
+     already did that.  */
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::rshifts", result, *this, cnt);
+#endif
+
+  return result;
+}
+
+/* Rotate THIS right by Y within its precision.  */
+
+wide_int
+wide_int::rrotate (const wide_int &y) const
+{
+  return rrotate (y.extract_to_hwi (0, HOST_BITS_PER_WIDE_INT));
+}
+
+/* Rotate THIS right by CNT within its precision.  */
+
+wide_int
+wide_int::rrotate (int cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (precision - cnt, NONE);
+  right = rshiftu (cnt, NONE);
+  result = left | right;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int::rrotate", result, *this, cnt);
+#endif
+  return result;
+}
+
+/*
+ * Private utilities.
+ */
+/* Decompress THIS for at least TARGET bits into a result with MODE.  */
+
+wide_int
+wide_int::decompress (unsigned int target, unsigned int bs, unsigned int prec) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (target);
+  HOST_WIDE_INT mask;
+  int len, i;
+
+  result.bitsize = bs;
+  result.precision = prec;
+  result.len = blocks_needed;
+
+  for (i = 0; i < this->len; i++)
+    result.val[i] = val[i];
+
+  len = this->len;
+
+  /* One could argue that this should just ice.  */
+  if (target > result.precision)
+    return result;
+
+  /* The extension that we are doing here is not sign extension, it is
+     decompression.  */
+  mask = sign_mask ();
+  while (len < blocks_needed)
+    result.val[len++] = mask;
+
+  return result;
+}
+
+
+/*
+ * Private debug printing routines.
+ */
+
+/* The debugging routines print results of wide operations into the
+   dump files of the respective passes in which they were called.  */
+char *
+wide_int::dump (char* buf) const
+{
+  int i;
+  int l;
+  const char * sep = "";
+
+  l = sprintf (buf, "[%d,%d (", bitsize, precision);
+  for (i = len - 1; i >= 0; i--)
+    {
+      l += sprintf (&buf[l], "%s" HOST_WIDE_INT_PRINT_HEX, sep, val[i]);
+      sep = " ";
+    }
+
+  gcc_assert (len != 0);
+
+  l += sprintf (&buf[l], ")]");
+
+  gcc_assert (l < MAX);
+  return buf;
+}
+
+#ifdef DEBUG_WIDE_INT
+void
+debug_vw (const char* name, int r, const wide_int& o0)
+{
+  char buf0[MAX];
+  fprintf (dump_file, "%s: %d = %s\n", name, r, o0.dump (buf0));
+}
+
+void
+debug_vwh (const char* name, int r, const wide_int &o0,
+	   HOST_WIDE_INT o1)
+{
+  char buf0[MAX];
+  fprintf (dump_file, "%s: %d = %s 0x"HOST_WIDE_INT_PRINT_HEX" \n", name, r,
+	   o0.dump (buf0), o1);
+}
+
+void
+debug_vww (const char* name, int r, const wide_int &o0,
+	   const wide_int &o1)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  fprintf (dump_file, "%s: %d = %s OP %s\n", name, r,
+	   o0.dump (buf0), o1.dump (buf1));
+}
+
+void
+debug_wv (const char* name, const wide_int &r, int v0)
+{
+  char buf0[MAX];
+  fprintf (dump_file, "%s: %s = %d\n",
+	   name, r.dump (buf0), v0);
+}
+
+void
+debug_wvv (const char* name, const wide_int &r, int v0, int v1)
+{
+  char buf0[MAX];
+  fprintf (dump_file, "%s: %s = %d %d\n",
+	   name, r.dump (buf0), v0, v1);
+}
+
+void
+debug_wvvv (const char* name, const wide_int &r, int v0,
+	    int v1, int v2)
+{
+  char buf0[MAX];
+  fprintf (dump_file, "%s: %s = %d %d %d\n",
+	   name, r.dump (buf0), v0, v1, v2);
+}
+
+void
+debug_wwv (const char* name, const wide_int &r,
+	   const wide_int &o0, int v0)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  fprintf (dump_file, "%s: %s = %s %d\n",
+	   name, r.dump (buf0),
+	   o0.dump (buf1), v0);
+}
+
+void
+debug_wwwvv (const char* name, const wide_int &r,
+	     const wide_int &o0, const wide_int &o1, int v0, int v1)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  char buf2[MAX];
+  fprintf (dump_file, "%s: %s = %s OP %s %d %d\n",
+	   name, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), v0, v1);
+}
+
+void
+debug_ww (const char* name, const wide_int &r, const wide_int &o0)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  fprintf (dump_file, "%s: %s = %s\n",
+	   name, r.dump (buf0),
+	   o0.dump (buf1));
+}
+
+void
+debug_www (const char* name, const wide_int &r,
+	   const wide_int &o0, const wide_int &o1)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  char buf2[MAX];
+  fprintf (dump_file, "%s: %s = %s OP %s\n",
+	   name, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2));
+}
+
+void
+debug_wwwv (const char* name, const wide_int &r,
+	    const wide_int &o0, const wide_int &o1, int v0)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  char buf2[MAX];
+  fprintf (dump_file, "%s: %s = %s OP %s %d\n",
+	   name, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), v0);
+}
+
+void
+debug_wwww (const char* name, const wide_int &r,
+	    const wide_int &o0, const wide_int &o1, const wide_int &o2)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  char buf2[MAX];
+  char buf3[MAX];
+  fprintf (dump_file, "%s: %s = %s OP %s OP %s\n",
+	   name, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), o2.dump (buf3));
+}
+#endif
+
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
new file mode 100644
index 0000000..efd2c01
--- /dev/null
+++ b/gcc/wide-int.h
@@ -0,0 +1,1109 @@
+/* Operations with very long integers.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef WIDE_INT_H
+#define WIDE_INT_H
+
+/* A wide integer is currently represented as a vector of
+   HOST_WIDE_INTs.  The vector contains enough elements to hold a
+   value of MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT which is
+   a derived for each host target combination.  The values are stored
+   in the vector with the least signicant HOST_BITS_PER_WIDE_INT bits
+   of the value stored in element 0.
+
+   A wide_int contains four fields: the vector (VAL), the bitsize,
+   precision and a length, (LEN).  The length is the number of HWIs
+   needed to represent the value.
+
+   Since most integers used in a compiler are small values, it is
+   generally profitable to use a representation of the value that is
+   shorter than the modes precision.  LEN is used to indicate the
+   number of elements of the vector that are in use.  When LEN *
+   HOST_BITS_PER_WIDE_INT < the precision, the value has been
+   compressed.  The values of the elements of the vector greater than
+   LEN - 1. are all equal to the highest order bit of LEN.
+
+   The representation does not contain any information about
+   signedness of the represented value, so it can be used to represent
+   both signed and unsigned numbers.  For operations where the results
+   depend on signedness (division, comparisons), the signedness must
+   be specified separately.  For operations where the signness
+   matters, one of the operands to the operation specifies either
+   wide_int::SIGNED or wide_int::UNSIGNED.
+
+   All constructors for wide_int take either a bitsize and precision,
+   an enum machine_mode or tree_type.  */
+
+
+#ifndef GENERATOR_FILE
+#include "tree.h"
+#include "hwint.h"
+#include "options.h"
+#include "tm.h"
+#include "insn-modes.h"
+#include "machmode.h"
+#include "double-int.h"
+#include <gmp.h>
+#include "insn-modes.h"
+
+
+class wide_int {
+  /* Internal representation.  */
+  
+  /* VAL is set to a size that is capable of computing a full
+     multiplication on the largest mode that is represented on the
+     target.  The full multiplication is use by tree-vrp.  If
+     operations are added that require larger buffers, then VAL needs
+     to be changed.  */
+  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  unsigned short len;
+  unsigned int bitsize;
+  unsigned int precision;
+
+ public:
+  enum ShiftOp {
+    NONE,
+    /* There are two uses for the wide-int shifting functions.  The
+       first use is as an emulation of the target hardware.  The
+       second use is as service routines for other optimizations.  The
+       first case needs to be identified by passing TRUNC as the value
+       of ShiftOp so that shift amount is properly handled according to the
+       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
+       amount is always truncated by the bytesize of the mode of
+       THIS.  */
+    TRUNC
+  };
+
+  enum SignOp {
+    /* Many of the math functions produce different results depending
+       on if they are SIGNED or UNSIGNED.  In general, there are two
+       different functions, whose names are prefixed with an 'S" and
+       or an 'U'.  However, for some math functions there is also a
+       routine that does not have the prefix and takes an SignOp
+       parameter of SIGNED or UNSIGNED.  */
+    SIGNED,
+    UNSIGNED
+  };
+
+  /* Conversions.  */
+
+  static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize, 
+			     unsigned int precision);
+  static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize, 
+			     unsigned int precision, bool *overflow);
+  static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, unsigned int bitsize, 
+			     unsigned int precision);
+  static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, unsigned int bitsize, 
+			     unsigned int precision, bool *overflow);
+
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type);
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type, 
+				   bool *overflow);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+				    bool *overflow);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+				    enum machine_mode mode);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+				    enum machine_mode mode, 
+				    bool *overflow);
+
+  static wide_int from_double_int (enum machine_mode, double_int);
+  static wide_int from_tree (const_tree);
+  static wide_int from_rtx (const_rtx, enum machine_mode);
+
+  HOST_WIDE_INT to_shwi () const;
+  HOST_WIDE_INT to_shwi (unsigned int prec) const;
+  unsigned HOST_WIDE_INT to_uhwi () const;
+  unsigned HOST_WIDE_INT to_uhwi (unsigned int prec) const;
+
+  /* Largest and smallest values that are represented in modes or precisions.  */
+
+  static wide_int max_value (unsigned int bitsize, unsigned int prec, SignOp sgn);
+  static wide_int max_value (const_tree type);
+  static wide_int max_value (enum machine_mode mode, SignOp sgn);
+  
+  static wide_int min_value (unsigned int bitsize, unsigned int prec, SignOp sgn);
+  static wide_int min_value (const_tree type);
+  static wide_int min_value (enum machine_mode mode, SignOp sgn);
+  
+  /* Small constants */
+
+  inline static wide_int minus_one (unsigned int bitsize, unsigned int prec);
+  inline static wide_int minus_one (const_tree type);
+  inline static wide_int minus_one (enum machine_mode mode);
+  inline static wide_int zero (unsigned int bitsize, unsigned int prec);
+  inline static wide_int zero (const_tree type);
+  inline static wide_int zero (enum machine_mode mode);
+  inline static wide_int one (unsigned int bitsize, unsigned int prec);
+  inline static wide_int one (const_tree type);
+  inline static wide_int one (enum machine_mode mode);
+  inline static wide_int two (unsigned int bitsize, unsigned int prec);
+  inline static wide_int two (const_tree type);
+  inline static wide_int two (enum machine_mode mode);
+  inline static wide_int ten (unsigned int bitsize, unsigned int prec);
+  inline static wide_int ten (const_tree type);
+  inline static wide_int ten (enum machine_mode mode);
+
+  /* Accessors.  */
+
+  inline unsigned short get_len () const;
+  inline unsigned int get_bitsize () const;
+  inline unsigned int get_precision () const;
+  inline unsigned int get_full_len () const;
+  inline HOST_WIDE_INT elt (unsigned int i) const;
+
+  /* The setters should rarely be used.   They are for the few places
+     where wide_ints are constructed inside some other class.  */
+  inline void set_len (unsigned int);
+  inline void set_bitsize (unsigned int);
+  inline void set_precision (unsigned int);
+  inline HOST_WIDE_INT& elt_ref (unsigned int i);
+  inline unsigned HOST_WIDE_INT& uelt_ref (unsigned int i);
+  inline const unsigned HOST_WIDE_INT& uelt_ref (unsigned int i) const;
+
+  /* Utility routines.  */
+
+  void canonize ();
+  wide_int force_to_size (unsigned int bitsize, 
+			  unsigned int precision) const;
+
+  /* Printing functions.  */
+
+  void print_dec (char *buf, SignOp sgn) const;
+  void print_dec (FILE *file, SignOp sgn) const;
+  void print_decs (char *buf) const;
+  void print_decs (FILE *file) const;
+  void print_decu (char *buf) const;
+  void print_decu (FILE *file) const;
+  void print_hex (char *buf) const;
+  void print_hex (FILE *file) const;
+
+  /* Comparative functions.  */
+
+  inline bool minus_one_p () const;
+  inline bool zero_p () const;
+  inline bool one_p () const;
+  inline bool neg_p () const;
+
+  bool operator == (const wide_int &y) const;
+  inline bool operator != (const wide_int &y) const;
+  inline bool gt_p (HOST_WIDE_INT x, SignOp sgn) const;
+  inline bool gt_p (const wide_int &x, SignOp sgn) const;
+  bool gts_p (HOST_WIDE_INT y) const;
+  inline bool gts_p (const wide_int &y) const;
+  bool gtu_p (unsigned HOST_WIDE_INT y) const;
+  inline bool gtu_p (const wide_int &y) const;
+
+  inline bool lt_p (const HOST_WIDE_INT x, SignOp sgn) const;
+  inline bool lt_p (const wide_int &x, SignOp sgn) const;
+  bool lts_p (HOST_WIDE_INT y) const;
+  bool lts_p (const wide_int &y) const;
+  bool ltu_p (unsigned HOST_WIDE_INT y) const;
+  bool ltu_p (const wide_int &y) const;
+
+  bool only_sign_bit_p (unsigned int prec) const;
+  bool only_sign_bit_p () const;
+  inline bool fits_uhwi_p () const;
+  inline bool fits_shwi_p () const;
+  bool fits_to_tree_p (const_tree type) const;
+  bool fits_u_p (unsigned int prec) const;
+  bool fits_s_p (unsigned int prec) const;
+
+  /* Min and max */
+
+  inline wide_int smin (const wide_int &op1) const;
+  inline wide_int smax (const wide_int &op1) const;
+  inline wide_int umin (const wide_int &op1) const;
+  inline wide_int umax (const wide_int &op1) const;
+
+  /* Extension  */
+
+  inline wide_int ext (unsigned int offset, SignOp sgn) const;
+  wide_int sext (unsigned int offset) const;
+  wide_int sext (enum machine_mode mode) const;
+  wide_int zext (unsigned int offset) const;
+  wide_int zext (enum machine_mode mode) const;
+
+  /* Masking, and Insertion  */
+
+  wide_int set_bit (unsigned int bitpos) const;
+  static wide_int set_bit_in_zero (unsigned int, 
+				   unsigned int bitsize, 
+				   unsigned int prec);
+  inline static wide_int set_bit_in_zero (unsigned int, 
+					  enum machine_mode mode);
+  inline static wide_int set_bit_in_zero (unsigned int, const_tree type);
+  wide_int insert (const wide_int &op0, unsigned int offset,
+		   unsigned int width) const;
+  static wide_int mask (unsigned int start, bool negate, 
+			unsigned int bitsize, unsigned int prec);
+  inline static wide_int mask (unsigned int start, bool negate, 
+			       enum machine_mode mode);
+  inline static wide_int mask (unsigned int start, bool negate,
+			       const_tree type);
+  wide_int bswap () const;
+  static wide_int shifted_mask (unsigned int start, unsigned int width,
+				bool negate,
+				unsigned int bitsize, unsigned int prec);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, enum machine_mode mode);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, const_tree type);
+  inline HOST_WIDE_INT sign_mask () const;
+
+  /* Logicals */
+
+  wide_int operator & (const wide_int &y) const;
+  wide_int and_not (const wide_int &y) const;
+  wide_int operator ~ () const;
+  wide_int or_not (const wide_int &y) const;
+  wide_int operator | (const wide_int &y) const;
+  wide_int operator ^ (const wide_int &y) const;
+
+  /* Arithmetic operation functions, alpha sorted.  */
+  wide_int abs () const;
+  wide_int operator + (const wide_int &y) const;
+  wide_int operator + (HOST_WIDE_INT y) const;
+  wide_int operator + (unsigned HOST_WIDE_INT y) const;
+  wide_int add (const wide_int &x, SignOp sgn, bool *overflow) const;
+  wide_int clz (unsigned int bitsize, unsigned int prec) const;
+  int clz () const;
+  wide_int clrsb (unsigned int bitsize, unsigned int prec) const;
+  int clrsb () const;
+  int cmp (const wide_int &y, SignOp sgn) const;
+  int cmps (const wide_int &y) const;
+  int cmpu (const wide_int &y) const;
+  wide_int ctz (unsigned int bitsize, unsigned int prec) const;
+  int ctz () const;
+  int exact_log2 () const;
+  wide_int ffs () const;
+  wide_int operator * (const wide_int &y) const;
+  wide_int mul (const wide_int &x, SignOp sgn, bool *overflow) const;
+  inline wide_int smul (const wide_int &x, bool *overflow) const;
+  inline wide_int umul (const wide_int &x, bool *overflow) const;
+  wide_int mul_full (const wide_int &x, SignOp sgn) const;
+  inline wide_int umul_full (const wide_int &x) const;
+  inline wide_int smul_full (const wide_int &x) const;
+  wide_int mul_high (const wide_int &x, SignOp sgn) const;
+  wide_int neg () const;
+  wide_int neg_overflow (bool *z) const;
+  wide_int parity (unsigned int bitsize, unsigned int prec) const;
+  int popcount () const;
+  wide_int popcount (unsigned int bitsize, unsigned int prec) const;
+  wide_int operator - (const wide_int &y) const;
+  wide_int operator - (HOST_WIDE_INT y) const;
+  wide_int operator - (unsigned HOST_WIDE_INT y) const;
+  wide_int sub (const wide_int &x, SignOp sgn, bool *overflow) const;
+
+  /* Divison and mod.  These are the ones that are actually used, but
+     there are a lot of them.  */
+
+  wide_int div_trunc (const wide_int &divisor, SignOp sgn) const;
+  wide_int div_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int sdiv_trunc (const wide_int &divisor) const;
+  inline wide_int udiv_trunc (const wide_int &divisor) const;
+
+  wide_int div_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int udiv_floor (const wide_int &divisor) const;
+  inline wide_int sdiv_floor (const wide_int &divisor) const;
+  wide_int div_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  wide_int div_round (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+
+  wide_int divmod_trunc (const wide_int &divisor, wide_int *mod, SignOp sgn) const;
+  inline wide_int sdivmod_trunc (const wide_int &divisor, wide_int *mod) const;
+  inline wide_int udivmod_trunc (const wide_int &divisor, wide_int *mod) const;
+
+  wide_int divmod_floor (const wide_int &divisor, wide_int *mod, SignOp sgn) const;
+  inline wide_int sdivmod_floor (const wide_int &divisor, wide_int *mod) const;
+
+  wide_int mod_trunc (const wide_int &divisor, SignOp sgn) const;
+  wide_int mod_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int smod_trunc (const wide_int &divisor) const;
+  inline wide_int umod_trunc (const wide_int &divisor) const;
+
+  wide_int mod_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int umod_floor (const wide_int &divisor) const;
+  wide_int mod_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  wide_int mod_round (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+
+  /* Shifting rotating and extracting.  */
+  HOST_WIDE_INT extract_to_hwi (int offset, int width) const;
+
+  wide_int lshift (const wide_int &y, ShiftOp z = NONE) const;
+  wide_int lshift (unsigned int y, ShiftOp z, unsigned int bitsize, 
+		   unsigned int precision) const;
+  wide_int lshift (unsigned int y, ShiftOp z = NONE) const;
+
+  wide_int lrotate (const wide_int &y) const;
+  wide_int lrotate (unsigned int y) const;
+
+  wide_int rshift (int y, SignOp sgn) const;
+  inline wide_int rshift (const wide_int &y, SignOp sgn, ShiftOp z = NONE) const;
+  wide_int rshiftu (const wide_int &y, ShiftOp z = NONE) const;
+  wide_int rshiftu (unsigned int y, ShiftOp z = NONE) const;
+  wide_int rshifts (const wide_int &y, ShiftOp z = NONE) const;
+  wide_int rshifts (unsigned int y, ShiftOp z = NONE) const;
+
+  wide_int rrotate (const wide_int &y) const;
+  wide_int rrotate (int y) const;
+
+  static const int DUMP_MAX = (2 * (MAX_BITSIZE_MODE_ANY_INT / 4
+			       + MAX_BITSIZE_MODE_ANY_INT 
+				    / HOST_BITS_PER_WIDE_INT + 32));
+  char *dump (char* buf) const;
+ private:
+
+  /* Private utility routines.  */
+  wide_int decompress (unsigned int target, unsigned int bitsize, 
+		       unsigned int precision) const;
+  static wide_int add_overflow (const wide_int *op0, const wide_int *op1,
+				wide_int::SignOp sgn, bool *overflow);
+  static wide_int sub_overflow (const wide_int *op0, const wide_int *op1, 
+				wide_int::SignOp sgn, bool *overflow);
+};
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with bitsize
+   and precision taken from MODE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, enum machine_mode mode)
+{
+  return wide_int::set_bit_in_zero (bitpos, GET_MODE_BITSIZE (mode),
+				    GET_MODE_PRECISION (mode));
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with bitsize
+   and precision taken from TYPE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, const_tree type)
+{
+
+  return wide_int::set_bit_in_zero (bitpos, 
+				    GET_MODE_BITSIZE (TYPE_MODE (type)),
+				    TYPE_PRECISION (type));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.   The result is made with bitsize
+   and precision taken from MODE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, enum machine_mode mode)
+{
+  return wide_int::mask (width, negate, 
+			 GET_MODE_BITSIZE (mode),
+			 GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with bitsize
+   and precision taken from TYPE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, const_tree type)
+{
+
+  return wide_int::mask (width, negate, 
+			 GET_MODE_BITSIZE (TYPE_MODE (type)),
+			 TYPE_PRECISION (type));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the bits
+   above that up to the precision are zeros.  The result is inverted
+   if NEGATE is true.  The result is made with bitsize and precision
+   taken from MODE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, enum machine_mode mode)
+{
+  return wide_int::shifted_mask (start, width, negate, 
+				 GET_MODE_BITSIZE (mode),
+				 GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with bitsize
+   and precision taken from TYPE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, const_tree type)
+{
+
+  return wide_int::shifted_mask (start, width, negate, 
+				 GET_MODE_BITSIZE (TYPE_MODE (type)),
+				 TYPE_PRECISION (type));
+}
+
+/* Produce 0 or -1 that is the smear of the sign bit.  */
+
+HOST_WIDE_INT
+wide_int::sign_mask () const
+{
+  int i = len - 1;
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
+	    >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* VRP appears to be badly broken and this is a very ugly fix.  */
+  if (i >= 0)
+    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
+
+  gcc_unreachable ();
+}
+
+/* Conversions */
+
+/* Convert OP1 into a wide_int with parameters taken from TYPE.  */
+
+wide_int
+wide_int::from_hwi (HOST_WIDE_INT op0, const_tree type)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return wide_int::from_uhwi (op0, bitsize, prec);
+  else
+    return wide_int::from_shwi (op0, bitsize, prec);
+}
+
+/* Convert OP1 into a wide_int with parameters taken from TYPE.  If
+   the value does not fit, set OVERFLOW.  */
+
+wide_int
+wide_int::from_hwi (HOST_WIDE_INT op0, const_tree type, 
+			    bool *overflow)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return wide_int::from_uhwi (op0, bitsize, prec, overflow);
+  else
+    return wide_int::from_shwi (op0, bitsize, prec, overflow);
+}
+
+/* Convert signed OP1 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_shwi (op0, bitsize, prec);
+}
+
+/* Convert signed OP1 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+	   bool *overflow)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_shwi (op0, bitsize, prec, overflow);
+}
+
+/* Convert unsigned OP1 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_uhwi (op0, bitsize, prec);
+}
+
+/* Convert unsigned OP1 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode, 
+			     bool *overflow)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_uhwi (op0, bitsize, prec, overflow);
+}
+
+/* Small constants.  */
+
+/* Return a wide int of -1 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::minus_one (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (-1, bs, prec);
+}
+
+/* Return a wide int of -1 with TYPE.  */
+
+wide_int
+wide_int::minus_one (const_tree type)
+{
+  return wide_int::from_shwi (-1, TYPE_MODE (type));
+}
+
+/* Return a wide int of -1 with MODE.  */
+
+wide_int
+wide_int::minus_one (enum machine_mode mode)
+{
+  return wide_int::from_shwi (-1, mode);
+}
+
+
+/* Return a wide int of 0 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::zero (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (0, bs, prec);
+}
+
+/* Return a wide int of 0 with TYPE.  */
+
+wide_int
+wide_int::zero (const_tree type)
+{
+  return wide_int::from_shwi (0, TYPE_MODE (type));
+}
+
+/* Return a wide int of 0 with MODE.  */
+
+wide_int
+wide_int::zero (enum machine_mode mode)
+{
+  return wide_int::from_shwi (0, mode);
+}
+
+
+/* Return a wide int of 1 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::one (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (1, bs, prec);
+}
+
+/* Return a wide int of 1 with TYPE.  */
+
+wide_int
+wide_int::one (const_tree type)
+{
+  return wide_int::from_shwi (1, TYPE_MODE (type));
+}
+
+/* Return a wide int of 1 with MODE.  */
+
+wide_int
+wide_int::one (enum machine_mode mode)
+{
+  return wide_int::from_shwi (1, mode);
+}
+
+
+/* Return a wide int of 2 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::two (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (2, bs, prec);
+}
+
+/* Return a wide int of 2 with TYPE.  */
+
+wide_int
+wide_int::two (const_tree type)
+{
+  return wide_int::from_shwi (2, TYPE_MODE (type));
+}
+
+/* Return a wide int of 2 with MODE.  */
+
+wide_int
+wide_int::two (enum machine_mode mode)
+{
+  return wide_int::from_shwi (2, mode);
+}
+
+
+/* Return a wide int of 10 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::ten (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (10, bs, prec);
+}
+
+/* Return a wide int of 10 with TYPE.  */
+
+wide_int
+wide_int::ten (const_tree type)
+{
+  return wide_int::from_shwi (10, TYPE_MODE (type));
+}
+
+/* Return a wide int of 10 with MODE.  */
+
+wide_int
+wide_int::ten (enum machine_mode mode)
+{
+  return wide_int::from_shwi (10, mode);
+}
+
+
+/* Public accessors for the interior of a wide int.  */
+
+/* Get the number of host wide ints actually represented within the
+   wide int.  */
+
+unsigned short
+wide_int::get_len () const
+{
+  return len;
+}
+
+/* Get bitsize of the value represented within the wide int.  */
+
+unsigned int
+wide_int::get_bitsize () const
+{
+  return bitsize;
+}
+
+/* Get precision of the value represented within the wide int.  */
+
+unsigned int
+wide_int::get_precision () const
+{
+  return precision;
+}
+
+/* Get the number of host wide ints needed to represent the precision
+   of the number.  NOTE that this should rarely be used.  The only
+   clients of this are places like dwarf2out where you need to
+   explicitly write all of the HWIs that are needed to represent the
+   value. */
+
+unsigned int
+wide_int::get_full_len () const
+{
+  return ((precision + HOST_BITS_PER_WIDE_INT - 1)
+	  / HOST_BITS_PER_WIDE_INT);
+}
+
+/* Get a particular element of the wide int.  */
+
+HOST_WIDE_INT
+wide_int::elt (unsigned int i) const
+{
+  return i >= len ? sign_mask () : val[i];
+}
+
+/* Set the number of host wide ints actually represented within the
+   wide int.  */
+
+void
+wide_int::set_len (unsigned int l)
+{
+  gcc_assert (l < MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT);
+  len = l;
+}
+
+/* Set the bitsize of the wide int.  */
+
+void
+wide_int::set_bitsize (unsigned int bs)
+{
+  bitsize = bs;
+}
+
+/* Set the precision of the wide int.  */
+
+void
+wide_int::set_precision (unsigned int prec)
+{
+  precision = prec;
+}
+
+/* Get a reference to a particular element of the wide int.  Does not
+   check I against len as during construction we might want to set len
+   after creating the value.  */
+
+HOST_WIDE_INT&
+wide_int::elt_ref (unsigned int i)
+{
+  /* We check maximal size, not len.  */
+  gcc_assert (i < MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT); 
+
+  return val[i];
+}
+
+/* Get a reference to a particular element of the wide int as an
+   unsigned quantity.  Does not check I against len as during
+   construction we might want to set len after creating the value.  */
+
+unsigned HOST_WIDE_INT&
+wide_int::uelt_ref (unsigned int i)
+{
+  return *(unsigned HOST_WIDE_INT *)&elt_ref (i);
+}
+
+/* Get a reference to a particular element of the wide int as a
+   constant unsigned quantity.  Does not check I against len as during
+   construction we might want to set len after creating the value.  */
+
+const unsigned HOST_WIDE_INT&
+wide_int::uelt_ref (unsigned int i) const
+{
+  /* We check maximal size, not len.  */
+  gcc_assert (i < MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT); 
+
+  return *(const unsigned HOST_WIDE_INT *)&val[i];
+}
+
+/* Return true if THIS is -1.  */
+
+bool
+wide_int::minus_one_p () const
+{
+  return len == 1 && val[0] == (HOST_WIDE_INT)-1;
+}
+
+/* Return true if THIS is 0.  */
+
+bool
+wide_int::zero_p () const
+{
+  return len == 1 && val[0] == 0;
+}
+
+/* Return true if THIS is 1.  */
+
+bool
+wide_int::one_p () const
+{
+  return len == 1 && val[0] == 1;
+}
+
+/* Return true if THIS is negative.  */
+
+bool
+wide_int::neg_p () const
+{
+  return sign_mask () != 0;
+}
+
+/* Return true if THIS is not equal to OP1. */ 
+
+bool
+wide_int::operator != (const wide_int &op1) const
+{
+  return !(*this == op1);
+}  
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::gt_p (HOST_WIDE_INT op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return gts_p (op1);
+  else
+    return gtu_p (op1);
+}  
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::gt_p (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return op1.lts_p (*this);
+  else
+    return op1.ltu_p (*this);
+}  
+
+/* Return true if THIS is signed greater than OP1.  */
+
+bool
+wide_int::gts_p (const wide_int &op1) const
+{
+  return op1.lts_p (*this);
+}  
+
+/* Return true if THIS is unsigned greater than OP1.  */
+
+bool
+wide_int::gtu_p (const wide_int &op1) const
+{
+  return op1.ltu_p (*this);
+}  
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::lt_p (HOST_WIDE_INT op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (op1);
+  else
+    return ltu_p (op1);
+}  
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::lt_p (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (op1);
+  else
+    return ltu_p (op1);
+}  
+
+/* Return the signed min of THIS and OP1. */
+
+wide_int
+wide_int::smin (const wide_int &op1) const
+{
+  return lts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed max of THIS and OP1. */
+
+wide_int
+wide_int::smax (const wide_int &op1) const
+{
+  return gts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::umin (const wide_int &op1) const
+{
+  return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::umax (const wide_int &op1) const
+{
+  return gtu_p (op1) ? (*this) : op1;
+}  
+
+
+/* Return true if THIS fits in a HOST_WIDE_INT with no loss of
+   precision.  */
+
+bool
+wide_int::fits_shwi_p () const
+{
+  return len == 1;
+}
+
+/* Return true if THIS fits in an unsigned HOST_WIDE_INT with no loss
+   of precision.  */
+
+bool
+wide_int::fits_uhwi_p () const
+{
+  return len == 1 
+    || (len == 2 && val[1] == (HOST_WIDE_INT)-1);
+}
+
+/* Return THIS extended to PREC.  The signness of the extension is
+   specified by OP.  */
+
+wide_int 
+wide_int::ext (unsigned int prec, SignOp z) const
+{
+  if (z == UNSIGNED)
+    return zext (prec);
+  else
+    return zext (prec);
+}
+
+/* Signed multiply THIS and OP1.  The result is the same precision as
+   the operands.  OVERFLOW is set true if the result overflows.  */
+
+wide_int
+wide_int::smul (const wide_int &x, bool *overflow) const
+{
+  return mul (x, SIGNED, overflow);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is the same precision
+   as the operands.  OVERFLOW is set true if the result overflows.  */
+
+wide_int
+wide_int::umul (const wide_int &x, bool *overflow) const
+{
+  return mul (x, UNSIGNED, overflow);
+}
+
+/* Signed multiply THIS and OP1.  The result is twice the precision as
+   the operands.  */
+
+wide_int
+wide_int::smul_full (const wide_int &x) const
+{
+  return mul_full (x, SIGNED);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is twice the precision
+   as the operands.  */
+
+wide_int
+wide_int::umul_full (const wide_int &x) const
+{
+  return mul_full (x, UNSIGNED);
+}
+
+/* Signed divide with truncation of result.  */
+
+wide_int
+wide_int::sdiv_trunc (const wide_int &divisor) const
+{
+  return div_trunc (divisor, SIGNED);
+}
+
+/* Unsigned divide with truncation of result.  */
+
+wide_int
+wide_int::udiv_trunc (const wide_int &divisor) const
+{
+  return div_trunc (divisor, UNSIGNED);
+}
+
+/* Unsigned divide with floor truncation of result.  */
+
+wide_int
+wide_int::udiv_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return div_floor (divisor, UNSIGNED, &overflow);
+}
+
+/* Signed divide with floor truncation of result.  */
+
+wide_int
+wide_int::sdiv_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return div_floor (divisor, SIGNED, &overflow);
+}
+
+/* Signed divide/mod with truncation of result.  */
+
+wide_int
+wide_int::sdivmod_trunc (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_trunc (divisor, mod, SIGNED);
+}
+
+/* Unsigned divide/mod with truncation of result.  */
+
+wide_int
+wide_int::udivmod_trunc (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_trunc (divisor, mod, UNSIGNED);
+}
+
+/* Signed divide/mod with floor truncation of result.  */
+
+wide_int
+wide_int::sdivmod_floor (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_floor (divisor, mod, SIGNED);
+}
+
+/* Signed mod with truncation of result.  */
+
+wide_int
+wide_int::smod_trunc (const wide_int &divisor) const
+{
+  return mod_trunc (divisor, SIGNED);
+}
+
+/* Unsigned mod with truncation of result.  */
+
+wide_int
+wide_int::umod_trunc (const wide_int &divisor) const
+{
+  return mod_trunc (divisor, UNSIGNED);
+}
+
+/* Unsigned mod with floor truncation of result.  */
+
+wide_int
+wide_int::umod_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return mod_floor (divisor, UNSIGNED, &overflow);
+}
+
+/* Right shift THIS by Y.  SGN indicates the sign.  Z indicates the
+   truncation option.  */
+
+wide_int
+wide_int::rshift (const wide_int &y, SignOp sgn, ShiftOp z) const
+{
+  if (sgn == UNSIGNED)
+    return rshiftu (y, z);
+  else
+    return rshifts (y, z);
+}
+
+/* tree related routines.  */
+
+extern tree wide_int_to_tree (tree type, const wide_int &cst);
+
+
+/* Conversion to and from GMP integer representations.  */
+
+void mpz_set_wide_int (mpz_t, wide_int, bool);
+wide_int mpz_get_wide_int (const_tree, mpz_t, bool);
+#endif /* GENERATOR FILE */
+
+#endif /* WIDE_INT_H */

[-- Attachment #3: p4-1.clog --]
[-- Type: text/plain, Size: 190 bytes --]

2012-10-9  Kenneth Zadeck <zadeck@naturalbridge.com>

	* wide-int.c: New file containing implementation of wide_int class.
	* wide-int.h: New file containing public spec for wide_int class.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - patch 5 - the rest of the rtl stuff.
  2012-10-08 19:43                                       ` Richard Sandiford
  2012-10-09 15:10                                         ` patch to fix constant math - 4th patch - the wide-int class Kenneth Zadeck
@ 2012-10-09 18:51                                         ` Kenneth Zadeck
  2012-10-19 16:52                                           ` Richard Sandiford
  2012-11-09 13:22                                         ` patch to fix constant math - third small patch Kenneth Zadeck
  2 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-09 18:51 UTC (permalink / raw)
  To: Richard Guenther, Mike Stump, gcc-patches, rdsandiford

[-- Attachment #1: Type: text/plain, Size: 430 bytes --]

This patch is the rest of the rtl stuff.  Richard Sandiford, the only 
parts that you have not seen are the parts that relate to changes in abi 
that Richi wanted.   The only interesting ones are the calls to 
immed_wide_int_const that now have to take a mode since there is no mode 
buried inside of the wide-int any more.

i think i got these all correct and i did test it.

ok to commit after the other 4 patches go in?

kenny

[-- Attachment #2: p5-1.clog --]
[-- Type: text/plain, Size: 4555 bytes --]

2012-10-9  Kenneth Zadeck <zadeck@naturalbridge.com>

	* Makefile.in (wide-int.c, wide-int.h): New files.
	* alias.c  (rtx_equal_for_memref_p): Fixed comment.
	* builtins.c (c_getstr, c_readstr, expand_builtin_signbit): 
	Make to work with any size int.
	* combine.c (try_combine, subst): Changed to support any 
	size integer.
	* coretypes.h (hwivec_def, hwivec, const_hwivec): New.
	* cse.c (hash_rtx_cb): Added CONST_WIDE_INT case are
	modified DOUBLE_INT case.
	* cselib.c (rtx_equal_for_cselib_1, cselib_hash_rtx):
	Added CONST_WIDE_INT case.
	* defaults.h (TARGET_SUPPORTS_WIDE_INT): New.
	* doc/rtl.texi (CONST_DOUBLE, CONST_WIDE_INT): Updated.
	* doc/tm.texi (TARGET_SUPPORTS_WIDE_INT): New.	
	* doc/tm.texi.in (TARGET_SUPPORTS_WIDE_INT): New.
	* dojump.c (prefer_and_bit_test): Use wide int api.
	* dwarf2out.c (dw_val_equal_p, size_of_loc_descr,
	output_loc_operands, print_die, attr_checksum, same_dw_val_p,
	size_of_die, value_format, output_die, mem_loc_descriptor,
	loc_descriptor, extract_int, add_const_value_attribute,
	hash_loc_operands, compare_loc_operands): Add support for wide-ints.
	(add_AT_wide): New function.
	* dwarf2out.h (enum dw_val_class): Added dw_val_class_wide_int.
	* emit-rtl.c (const_wide_int_htab): Add marking.
	(const_wide_int_htab_hash, const_wide_int_htab_eq,
	lookup_const_wide_int, immed_wide_int_const): New functions.
	(const_double_htab_hash, const_double_htab_eq,
	rtx_to_double_int, immed_double_const): Conditionally 
	changed CONST_DOUBLE behavior.
 	(immed_double_const, init_emit_once): Changed to support wide-int.
	* explow.c (plus_constant): Now uses wide-int api.
	* expmed.c (mask_rtx, lshift_value): Now uses wide-int.
 	(expand_mult, expand_smod_pow2): Make to work with any size int.
	(make_tree): Added CONST_WIDE_INT case.
	* expr.c (convert_modes): Added support for any size int.
	(emit_group_load_1): Added todo for place that still does not
	allow large ints.
	(store_expr, expand_constructor): Fixed comments.
	(expand_expr_real_2, expand_expr_real_1,
	reduce_to_bit_field_precision, const_vector_from_tree):
	Converted to use wide-int api.
	* final.c (output_addr_const): Added CONST_WIDE_INT case.
	* genemit.c (gen_exp): Added CONST_WIDE_INT case.
	* gengenrtl.c (excluded_rtx): Added CONST_WIDE_INT case.
	* gengtype.c (wide-int): New type.
	* genpreds.c (write_one_predicate_function): Fixed comment.
	(add_constraint): Added CONST_WIDE_INT test.
	(write_tm_constrs_h): Do not emit hval or lval if target
	supports wide integers.
	* gensupport.c (const_wide_int_operand,
	const_scalar_int_operand): New.
	* ggc-zone.c (ggc_alloc_typed_stat): Added
	gt_ggc_e_10hwivec_def case.
	* ggc.h (ggc_alloc_hwivec_sized): New.
	* optabs.c (expand_subword_shift, expand_doubleword_shift,
	expand_absneg_bit, expand_absneg_bit, expand_copysign_absneg,
	expand_copysign_bit): Made to work with any size int.  
	* postreload.c (reload_cse_simplify_set):  Now uses wide-int api.
	* print-rtl.c (print_rtx): Added CONST_WIDE_INT case.
	* read-rtl.c (validate_const_wide_int): New function.
	(read_rtx_code): Added CONST_WIDE_INT case.
	* recog.c (const_scalar_int_operand, const_double_operand):
	New versions if target supports wide integers.
	(const_wide_int_operand): New function.
	* rtl.c (DEF_RTL_EXPR): Added CONST_WIDE_INT case.
	(rtx_size): Ditto.
	(rtx_alloc_stat, hwivec_output_hex, hwivec_check_failed_bounds):
	New functions.
	(iterative_hash_rtx): Added CONST_WIDE_INT case.
	* rtl.def (CONST_WIDE_INT): New.
	* rtl.h (hwivec_def): New function.
	(HWI_GET_NUM_ELEM, HWI_PUT_NUM_ELEM, CONST_WIDE_INT_P,
	CONST_SCALAR_INT_P, XHWIVEC_ELT, HWIVEC_CHECK, CONST_WIDE_INT_VEC,
	CONST_WIDE_INT_NUNITS, CONST_WIDE_INT_ELT, rtx_alloc_v): New macros.
	(chain_next): Added hwiv case.
	(CASE_CONST_SCALAR_INT, CONST_INT, CONST_WIDE_INT):  Added new
	defs if target supports wide ints.
	* rtlanal.c (commutative_operand_precedence, split_double):
	Added CONST_WIDE_INT case.
	* sched-vis.c (print_value): Added CONST_WIDE_INT case are
	modified DOUBLE_INT case.
	* sel-sched-ir.c (lhs_and_rhs_separable_p): Fixed comment
	* simplify-rtx.c (mode_signbit_p,
	simplify_const_unary_operation, simplify_binary_operation_1,
	simplify_const_binary_operation,
	simplify_const_relational_operation, simplify_immed_subreg):
	Make work with any size int.  .
	* tree-ssa-address.c (addr_for_mem_ref): Changes to use
	wide-int rather than double-int.
	* tree.c (wide_int_to_tree): New function.
	* var-tracking.c (loc_cmp): Added CONST_WIDE_INT case.
	* varasm.c (const_rtx_hash_1): Added CONST_WIDE_INT case.

[-- Attachment #3: p5-1.diff --]
[-- Type: text/x-patch, Size: 138559 bytes --]

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 77ba4df..af89420 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -841,7 +841,7 @@ COMMON_TARGET_DEF_H = common/common-target-def.h \
 RTL_BASE_H = coretypes.h rtl.h rtl.def $(MACHMODE_H) reg-notes.def \
   insn-notes.def $(INPUT_H) $(REAL_H) statistics.h $(VEC_H) \
   $(FIXED_VALUE_H) alias.h $(HASHTAB_H)
-FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h
+FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h wide-int.h
 RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h vecir.h
 RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H)
 READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
@@ -853,7 +853,7 @@ INTERNAL_FN_H = internal-fn.h $(INTERNAL_FN_DEF)
 TREE_H = coretypes.h tree.h all-tree.def tree.def c-family/c-common.def \
 	$(lang_tree_files) $(MACHMODE_H) tree-check.h $(BUILTINS_DEF) \
 	$(INPUT_H) statistics.h $(VEC_H) treestruct.def $(HASHTAB_H) \
-	double-int.h alias.h $(SYMTAB_H) $(FLAGS_H) vecir.h \
+	double-int.h wide-int.h alias.h $(SYMTAB_H) $(FLAGS_H) vecir.h \
 	$(REAL_H) $(FIXED_VALUE_H)
 REGSET_H = regset.h $(BITMAP_H) hard-reg-set.h
 BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) \
@@ -1433,6 +1433,7 @@ OBJS = \
 	varpool.o \
 	vmsdbgout.o \
 	web.o \
+	wide-int.o \
 	xcoffout.o \
 	$(out_object_file) \
 	$(EXTRA_OBJS) \
@@ -2640,6 +2641,7 @@ targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
    tree-ssa-alias.h $(TREE_FLOW_H)
 common/common-targhooks.o : common/common-targhooks.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(INPUT_H) $(TM_H) $(COMMON_TARGET_H) common/common-targhooks.h
+wide-int.o: wide-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
 
 bversion.h: s-bversion; @true
 s-bversion: BASE-VER
@@ -3834,15 +3836,16 @@ CFLAGS-gengtype-parse.o += -DGENERATOR_FILE
 build/gengtype-parse.o: $(BCONFIG_H)
 
 gengtype-state.o build/gengtype-state.o: gengtype-state.c $(SYSTEM_H) \
-  gengtype.h errors.h double-int.h version.h $(HASHTAB_H) $(OBSTACK_H) \
-  $(XREGEX_H)
+  gengtype.h errors.h double-int.h wide-int.h version.h $(HASHTAB_H)    \
+  $(OBSTACK_H) $(XREGEX_H)
 gengtype-state.o: $(CONFIG_H)
 CFLAGS-gengtype-state.o += -DGENERATOR_FILE
 build/gengtype-state.o: $(BCONFIG_H)
+wide-int.h: $(GTM_H) insn-modes.h
 
 gengtype.o build/gengtype.o : gengtype.c $(SYSTEM_H) gengtype.h 	\
-  rtl.def insn-notes.def errors.h double-int.h version.h $(HASHTAB_H) \
-  $(OBSTACK_H) $(XREGEX_H)
+  rtl.def insn-notes.def errors.h double-int.h wide-int.h version.h     \
+  $(HASHTAB_H) $(OBSTACK_H) $(XREGEX_H)
 gengtype.o: $(CONFIG_H)
 CFLAGS-gengtype.o += -DGENERATOR_FILE
 build/gengtype.o: $(BCONFIG_H)
diff --git a/gcc/alias.c b/gcc/alias.c
index 0c6a744..9e67823 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -1490,9 +1490,9 @@ rtx_equal_for_memref_p (const_rtx x, const_rtx y)
 
     case VALUE:
     CASE_CONST_UNIQUE:
-      /* There's no need to compare the contents of CONST_DOUBLEs or
-	 CONST_INTs because pointer equality is a good enough
-	 comparison for these nodes.  */
+      /* There's no need to compare the contents of CONST_DOUBLEs,
+	 CONST_INTs or CONST_WIDE_INTs because pointer equality is a
+	 good enough comparison for these nodes.  */
       return 0;
 
     default:
diff --git a/gcc/builtins.c b/gcc/builtins.c
index e6b10ea..67a9599 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -671,20 +671,25 @@ c_getstr (tree src)
   return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
 }
 
-/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
+/* Return a constant integer corresponding to target reading
    GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
 
 static rtx
 c_readstr (const char *str, enum machine_mode mode)
 {
-  HOST_WIDE_INT c[2];
+  wide_int c;
   HOST_WIDE_INT ch;
   unsigned int i, j;
+  c.set_bitsize (GET_MODE_BITSIZE (mode));
+  c.set_precision (GET_MODE_PRECISION (mode));
+  c.set_len ((GET_MODE_PRECISION (mode) + HOST_BITS_PER_WIDE_INT - 1)
+	     / HOST_BITS_PER_WIDE_INT);
+
+  for (i = 0; i < c.get_len (); i++)
+    c.elt_ref(i) = 0;
 
   gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
 
-  c[0] = 0;
-  c[1] = 0;
   ch = 1;
   for (i = 0; i < GET_MODE_SIZE (mode); i++)
     {
@@ -695,13 +700,14 @@ c_readstr (const char *str, enum machine_mode mode)
 	  && GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
 	j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
       j *= BITS_PER_UNIT;
-      gcc_assert (j < HOST_BITS_PER_DOUBLE_INT);
 
       if (ch)
 	ch = (unsigned char) str[i];
-      c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
+      c.elt_ref (j / HOST_BITS_PER_WIDE_INT) |= ch << (j % HOST_BITS_PER_WIDE_INT);
     }
-  return immed_double_const (c[0], c[1], mode);
+  
+  c.canonize ();
+  return immed_wide_int_const (c, mode);
 }
 
 /* Cast a target constant CST to target CHAR and if that value fits into
@@ -4990,12 +4996,13 @@ expand_builtin_signbit (tree exp, rtx target)
 
   if (bitpos < GET_MODE_BITSIZE (rmode))
     {
-      double_int mask = double_int_zero.set_bit (bitpos);
+      wide_int mask;
+      mask = wide_int::set_bit_in_zero (bitpos, rmode);
 
       if (GET_MODE_SIZE (imode) > GET_MODE_SIZE (rmode))
 	temp = gen_lowpart (rmode, temp);
       temp = expand_binop (rmode, and_optab, temp,
-			   immed_double_int_const (mask, rmode),
+			   immed_wide_int_const (mask, rmode),
 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
   else
diff --git a/gcc/combine.c b/gcc/combine.c
index cc167ce..07abfd1 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -2660,23 +2660,15 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
 	    offset = -1;
 	}
 
-      if (offset >= 0
-	  && (GET_MODE_PRECISION (GET_MODE (SET_DEST (temp)))
-	      <= HOST_BITS_PER_DOUBLE_INT))
+      if (offset >= 0)
 	{
-	  double_int m, o, i;
+	  wide_int o;
 	  rtx inner = SET_SRC (PATTERN (i3));
 	  rtx outer = SET_SRC (temp);
-
-	  o = rtx_to_double_int (outer);
-	  i = rtx_to_double_int (inner);
-
-	  m = double_int::mask (width);
-	  i &= m;
-	  m = m.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
-	  i = i.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
-	  o = o.and_not (m) | i;
-
+	  
+	  o = (wide_int::from_rtx (outer, GET_MODE (SET_DEST (temp)))
+	       .insert (wide_int::from_rtx (inner, GET_MODE (dest)),
+			offset, width));
 	  combine_merges++;
 	  subst_insn = i3;
 	  subst_low_luid = DF_INSN_LUID (i2);
@@ -2687,8 +2679,8 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
 	  /* Replace the source in I2 with the new constant and make the
 	     resulting insn the new pattern for I3.  Then skip to where we
 	     validate the pattern.  Everything was set up above.  */
-	  SUBST (SET_SRC (temp),
-		 immed_double_int_const (o, GET_MODE (SET_DEST (temp))));
+	  SUBST (SET_SRC (temp), 
+		 immed_wide_int_const (o, GET_MODE (SET_DEST (temp))));
 
 	  newpat = PATTERN (i2);
 
@@ -5110,7 +5102,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
 		  if (! x)
 		    x = gen_rtx_CLOBBER (mode, const0_rtx);
 		}
-	      else if (CONST_INT_P (new_rtx)
+	      else if (CONST_SCALAR_INT_P (new_rtx)
 		       && GET_CODE (x) == ZERO_EXTEND)
 		{
 		  x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index a2ca9c8..a257f44 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -56,6 +56,9 @@ typedef const struct rtx_def *const_rtx;
 struct rtvec_def;
 typedef struct rtvec_def *rtvec;
 typedef const struct rtvec_def *const_rtvec;
+struct hwivec_def;
+typedef struct hwivec_def *hwivec;
+typedef const struct hwivec_def *const_hwivec;
 union tree_node;
 typedef union tree_node *tree;
 union gimple_statement_d;
diff --git a/gcc/cse.c b/gcc/cse.c
index 1625598..e8fdf94 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -2335,15 +2335,23 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
                + (unsigned int) INTVAL (x));
       return hash;
 
+    case CONST_WIDE_INT:
+      {
+	int i;
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hash += CONST_WIDE_INT_ELT (x, i);
+      }
+      return hash;
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
 	 the integers representing the constant.  */
       hash += (unsigned int) code + (unsigned int) GET_MODE (x);
-      if (GET_MODE (x) != VOIDmode)
-	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      else
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	hash += ((unsigned int) CONST_DOUBLE_LOW (x)
 		 + (unsigned int) CONST_DOUBLE_HIGH (x));
+      else
+	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       return hash;
 
     case CONST_FIXED:
@@ -3759,6 +3767,7 @@ equiv_constant (rtx x)
 
       /* See if we previously assigned a constant value to this SUBREG.  */
       if ((new_rtx = lookup_as_function (x, CONST_INT)) != 0
+	  || (new_rtx = lookup_as_function (x, CONST_WIDE_INT)) != 0
           || (new_rtx = lookup_as_function (x, CONST_DOUBLE)) != 0
           || (new_rtx = lookup_as_function (x, CONST_FIXED)) != 0)
         return new_rtx;
diff --git a/gcc/cselib.c b/gcc/cselib.c
index d1eac00..433835b 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -909,6 +909,20 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, enum machine_mode memmode)
     case DEBUG_EXPR:
       return 0;
 
+    case CONST_WIDE_INT:
+      {
+	int i;
+	/* It would have been nice to have had a mode.  */
+	if (CONST_WIDE_INT_NUNITS (x) != CONST_WIDE_INT_NUNITS (y))
+	  return 0;
+
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  if (CONST_WIDE_INT_ELT (x, i) != CONST_WIDE_INT_ELT (y, i))
+	    return 0;
+
+	return 1;
+      }
+
     case DEBUG_IMPLICIT_PTR:
       return DEBUG_IMPLICIT_PTR_DECL (x)
 	     == DEBUG_IMPLICIT_PTR_DECL (y);
@@ -1099,15 +1113,23 @@ cselib_hash_rtx (rtx x, int create, enum machine_mode memmode)
       hash += ((unsigned) CONST_INT << 7) + INTVAL (x);
       return hash ? hash : (unsigned int) CONST_INT;
 
+    case CONST_WIDE_INT:
+      {
+	int i;
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hash += CONST_WIDE_INT_ELT (x, i);
+      }
+      return hash;
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
 	 the integers representing the constant.  */
       hash += (unsigned) code + (unsigned) GET_MODE (x);
-      if (GET_MODE (x) != VOIDmode)
-	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      else
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	hash += ((unsigned) CONST_DOUBLE_LOW (x)
 		 + (unsigned) CONST_DOUBLE_HIGH (x));
+      else
+	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       return hash ? hash : (unsigned int) CONST_DOUBLE;
 
     case CONST_FIXED:
diff --git a/gcc/defaults.h b/gcc/defaults.h
index 6eead33..628da32 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -1402,6 +1402,14 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define SWITCHABLE_TARGET 0
 #endif
 
+/* If the target supports integers that are wider than two
+   HOST_WIDE_INTs on the host compiler, then the target should define
+   TARGET_SUPPORTS_WIDE_INT and make the appropriate fixups.
+   Otherwise the compiler really is not robust.  */
+#ifndef TARGET_SUPPORTS_WIDE_INT
+#define TARGET_SUPPORTS_WIDE_INT 0
+#endif
+
 #endif /* GCC_INSN_FLAGS_H  */
 
 #endif  /* ! GCC_DEFAULTS_H */
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 07c480d..b18ada4 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -1511,17 +1511,20 @@ Similarly, there is only one object for the integer whose value is
 
 @findex const_double
 @item (const_double:@var{m} @var{i0} @var{i1} @dots{})
-Represents either a floating-point constant of mode @var{m} or an
-integer constant too large to fit into @code{HOST_BITS_PER_WIDE_INT}
-bits but small enough to fit within twice that number of bits (GCC
-does not provide a mechanism to represent even larger constants).  In
-the latter case, @var{m} will be @code{VOIDmode}.  For integral values
-constants for modes with more bits than twice the number in
-@code{HOST_WIDE_INT} the implied high order bits of that constant are
-copies of the top bit of @code{CONST_DOUBLE_HIGH}.  Note however that
-integral values are neither inherently signed nor inherently unsigned;
-where necessary, signedness is determined by the rtl operation
-instead.
+On older ports, this represents either a floating-point constant of
+mode @var{m} or an integer constant too large to fit into
+@code{HOST_BITS_PER_WIDE_INT} bits but small enough to fit within
+twice that number of bits (GCC does not provide a mechanism to
+represent even larger constants).  In the latter case, @var{m} will be
+@code{VOIDmode}.  For integral values constants for modes with more
+bits than twice the number in @code{HOST_WIDE_INT} the implied high
+order bits of that constant are copies of the top bit of
+@code{CONST_DOUBLE_HIGH}.  Note however that integral values are
+neither inherently signed nor inherently unsigned; where necessary,
+signedness is determined by the rtl operation instead.
+
+On more modern ports, @code{CONST_DOUBLE} only represents floating
+point values.   New ports define to TARGET_SUPPORTS_WIDE_INT to  
 
 @findex CONST_DOUBLE_LOW
 If @var{m} is @code{VOIDmode}, the bits of the value are stored in
@@ -1536,6 +1539,37 @@ machine's or host machine's floating point format.  To convert them to
 the precise bit pattern used by the target machine, use the macro
 @code{REAL_VALUE_TO_TARGET_DOUBLE} and friends (@pxref{Data Output}).
 
+@findex const_wide_int
+@item (const_wide_int:@var{m} @var{nunits} @var{elt0} @dots{})
+This contains a garbage collected array of @code{HOST_WIDE_INTS} that
+is large enough to hold any constant that can be represented on the
+target.  This form of rtl is only used on targets that define
+@code{TARGET_SUPPORTS_WIDE_INT} to be non zero and then
+@code{CONST_DOUBLES} are only used to hold floating point values.  If
+the target leaves @code{TARGET_SUPPORTS_WIDE_INT} defined as 0,
+@code{CONST_WIDE_INT}s are not used and @code{CONST_DOUBLE}s are as
+they were before.
+
+The values are stored in a compressed format.   The higher order
+0s or -1s are not represented if they are just the logical sign
+extension the number that is represented.   
+
+@findex CONST_WIDE_INT_VEC
+@item CONST_WIDE_INT_VEC (@var{code})
+Returns the entire array of @code{HOST_WIDE_INT}s that are used to
+store the value.   This macro should be rarely used.
+
+@findex CONST_WIDE_INT_NUNITS
+@item CONST_WIDE_INT_NUNITS (@var{code})
+The number of @code{HOST_WIDE_INT}s used to represent the number.
+Note that this generally be smaller than the number of
+@code{HOST_WIDE_INT}s implied by the mode size.
+
+@findex CONST_WIDE_INT_ELT
+@item CONST_WIDE_INT_NUNITS (@var{code},@var{i})
+Returns the @code{i}th element of the array.   Element 0 is contains
+the low order bits of the constant.
+
 @findex const_fixed
 @item (const_fixed:@var{m} @dots{})
 Represents a fixed-point constant of mode @var{m}.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index b36c764..802283a 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11311,3 +11311,48 @@ memory model bits are allowed.
 @deftypevr {Target Hook} {unsigned char} TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
 This value should be set if the result written by @code{atomic_test_and_set} is not exactly 1, i.e. the @code{bool} @code{true}.
 @end deftypevr
+@defmac TARGET_SUPPORTS_WIDE_INT
+
+On older ports, large integers are stored in @code{CONST_DOUBLE} rtl
+objects.  Newer ports define @code{TARGET_SUPPORTS_WIDE_INT} to be non
+zero to indicate tha large integers are stored in
+@code{CONST_WIDE_INT} rtl objects.  The @code{CONST_WIDE_INT} allows
+very large integer constants to be represented.  @code{CONST_DOUBLE}
+are limited to twice the size of host's @code{HOST_WIDE_INT}
+representation.
+
+Converting a port mostly requires looking for the places where
+@code{CONST_DOUBLES} are used with @code{VOIDmode} and replacing that
+code with code that accesses @code{CONST_WIDE_INT}s.  @code{"grep -i
+const_double"} at the port level gets you to 95% of the changes that
+need to be made.  There are a few places that require a deeper look.
+
+@itemize @bullet
+@item
+There is no equivalent to @code{hval} and @code{lval} for
+@code{CONST_WIDE_INT}s.  This would be difficult to express in the md
+language since there are a variable number of elements.
+
+Most ports only check that @code{hval} is either 0 or -1 to see if the
+value is small.  As mentioned above, this will no longer be necessary
+since small constants are always @code{CONST_INT}.  Of course there
+are still a few exceptions, the alpha's constraint used by the zap
+instruction certainly requires careful examination by C code.
+However, all the current code does is pass the hval and lval to C
+code, so evolving the c code to look at the @code{CONST_WIDE_INT} is
+not really a large change.
+
+@item
+Because there is no standard template that ports use to materialize
+constants, there is likely to be some futzing that is unique to each
+port in this code.
+
+@item
+The rtx costs may have to be adjusted to properly account for larger
+constants that are represented as @code{CONST_WIDE_INT}.
+@end itemize
+
+All and all it does not takes long to convert ports that the
+maintainer is familiar with.
+
+@end defmac
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 4858d97..c903037 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -11163,3 +11163,48 @@ memory model bits are allowed.
 @end deftypefn
 
 @hook TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
+@defmac TARGET_SUPPORTS_WIDE_INT
+
+On older ports, large integers are stored in @code{CONST_DOUBLE} rtl
+objects.  Newer ports define @code{TARGET_SUPPORTS_WIDE_INT} to be non
+zero to indicate tha large integers are stored in
+@code{CONST_WIDE_INT} rtl objects.  The @code{CONST_WIDE_INT} allows
+very large integer constants to be represented.  @code{CONST_DOUBLE}
+are limited to twice the size of host's @code{HOST_WIDE_INT}
+representation.
+
+Converting a port mostly requires looking for the places where
+@code{CONST_DOUBLES} are used with @code{VOIDmode} and replacing that
+code with code that accesses @code{CONST_WIDE_INT}s.  @code{"grep -i
+const_double"} at the port level gets you to 95% of the changes that
+need to be made.  There are a few places that require a deeper look.
+
+@itemize @bullet
+@item
+There is no equivalent to @code{hval} and @code{lval} for
+@code{CONST_WIDE_INT}s.  This would be difficult to express in the md
+language since there are a variable number of elements.
+
+Most ports only check that @code{hval} is either 0 or -1 to see if the
+value is small.  As mentioned above, this will no longer be necessary
+since small constants are always @code{CONST_INT}.  Of course there
+are still a few exceptions, the alpha's constraint used by the zap
+instruction certainly requires careful examination by C code.
+However, all the current code does is pass the hval and lval to C
+code, so evolving the c code to look at the @code{CONST_WIDE_INT} is
+not really a large change.
+
+@item
+Because there is no standard template that ports use to materialize
+constants, there is likely to be some futzing that is unique to each
+port in this code.
+
+@item
+The rtx costs may have to be adjusted to properly account for larger
+constants that are represented as @code{CONST_WIDE_INT}.
+@end itemize
+
+All and all it does not takes long to convert ports that the
+maintainer is familiar with.
+
+@end defmac
diff --git a/gcc/dojump.c b/gcc/dojump.c
index 66d3b04..a8c75ae 100644
--- a/gcc/dojump.c
+++ b/gcc/dojump.c
@@ -144,6 +144,7 @@ static bool
 prefer_and_bit_test (enum machine_mode mode, int bitnum)
 {
   bool speed_p;
+  wide_int mask = wide_int::set_bit_in_zero (bitnum, mode);
 
   if (and_test == 0)
     {
@@ -164,8 +165,7 @@ prefer_and_bit_test (enum machine_mode mode, int bitnum)
     }
 
   /* Fill in the integers.  */
-  XEXP (and_test, 1)
-    = immed_double_int_const (double_int_zero.set_bit (bitnum), mode);
+  XEXP (and_test, 1) = immed_wide_int_const (mask, mode);
   XEXP (XEXP (shift_test, 0), 1) = GEN_INT (bitnum);
 
   speed_p = optimize_insn_for_speed_p ();
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 98c88f7..bcf01e7 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1327,6 +1327,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;
@@ -1578,6 +1581,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 += (loc->dw_loc_oprnd2.v.val_wide.get_full_len ()
+		     * HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT);
+	    break;
 	  default:
 	    gcc_unreachable ();
 	  }
@@ -1755,6 +1762,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 = val2->v.val_wide.get_full_len ();
+	    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);
@@ -1957,6 +1978,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 = val2->v.val_wide.get_full_len ();
+	      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 ();
 	  }
@@ -3060,7 +3096,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 (wide_int *, unsigned char *);
 static void insert_float (const_rtx, unsigned char *);
 static rtx rtl_for_decl_location (tree);
 static bool add_location_or_const_value_attribute (dw_die_ref, tree, bool,
@@ -3557,6 +3593,20 @@ AT_unsigned (dw_attr_ref a)
 /* Add an unsigned double integer attribute value to a DIE.  */
 
 static inline void
+add_AT_wide (dw_die_ref die, enum dwarf_attribute attr_kind,
+	     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 = w;
+  add_dwarf_attr (die, &attr);
+}
+
+/* Add an unsigned double integer attribute value to a DIE.  */
+
+static inline void
 add_AT_double (dw_die_ref die, enum dwarf_attribute attr_kind,
 	       HOST_WIDE_INT high, unsigned HOST_WIDE_INT low)
 {
@@ -4867,6 +4917,19 @@ 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;
@@ -5022,6 +5085,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 (at->dw_attr_val.v.val_vec);
       break;
@@ -5292,6 +5358,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 (sizeof (at->dw_attr_val.v.val_vec));
@@ -5756,6 +5828,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)
@@ -7207,6 +7281,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 += (a->dw_attr_val.v.val_wide.get_full_len ()
+		   * HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
+	  if (a->dw_attr_val.v.val_wide.get_full_len () * 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)
@@ -7533,6 +7614,20 @@ value_format (dw_attr_ref a)
 	default:
 	  return DW_FORM_block1;
 	}
+    case dw_val_class_wide_int:
+      switch (a->dw_attr_val.v.val_wide.get_full_len () * 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))
@@ -7880,6 +7975,32 @@ output_die (dw_die_ref die)
 	  }
 	  break;
 
+	case dw_val_class_wide_int:
+	  {
+	    int i;
+	    int len = a->dw_attr_val.v.val_wide.get_full_len ();
+	    int l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
+	    if (len * HOST_BITS_PER_WIDE_INT > 64)
+	      dw2_asm_output_data (1, a->dw_attr_val.v.val_wide.get_full_len () * 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;
@@ -10848,9 +10969,8 @@ 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 
+      (wide_int::set_bit_in_zero (GET_MODE_PRECISION (mode) - 1, 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
@@ -11786,7 +11906,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
@@ -11798,13 +11927,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
+	    = wide_int::from_rtx (rtl, mode);
 	}
       break;
 
@@ -12275,7 +12417,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
@@ -12287,12 +12437,26 @@ 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))
+	{
+	  gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
+
+	  /* Note that a CONST_DOUBLE rtx could represent either an integer
+	     or a floating-point constant.  A CONST_DOUBLE is used whenever
+	     the constant requires more than one word in order to be
+	     adequately represented.  We output CONST_DOUBLEs as blocks.  */
+	  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
+	    = wide_int::from_rtx (rtl, mode);
 	}
       break;
 
@@ -12308,6 +12472,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))
@@ -12316,15 +12481,8 @@ 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);
-		    }
+		  wide_int val = wide_int::from_rtx (elt, imode);
+		  insert_wide_int (&val, p);
 		}
 	      break;
 
@@ -13962,22 +14120,27 @@ 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 (wide_int *val, unsigned char *dest)
 {
-  unsigned char *p0 = dest;
-  unsigned char *p1 = dest + sizeof (HOST_WIDE_INT);
+  int i;
 
   if (WORDS_BIG_ENDIAN)
-    {
-      p0 = p1;
-      p1 = dest;
-    }
-
-  insert_int ((HOST_WIDE_INT) val.low, sizeof (HOST_WIDE_INT), p0);
-  insert_int ((HOST_WIDE_INT) val.high, sizeof (HOST_WIDE_INT), p1);
+    for (i = (int)val->get_full_len () - 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 < (int)val->get_full_len (); 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.  */
@@ -14022,6 +14185,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,
+		   wide_int::from_rtx (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
@@ -14030,7 +14198,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);
@@ -14038,9 +14209,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;
 
@@ -14053,6 +14221,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))
 	  {
@@ -14060,15 +14229,8 @@ 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);
-		  }
+		wide_int val = wide_int::from_rtx (elt, imode);
+		insert_wide_int (&val, p);
 	      }
 	    break;
 
@@ -21871,6 +22033,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;
@@ -21949,6 +22114,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 ();
 	  }
@@ -22094,6 +22262,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:
@@ -22130,6 +22300,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 ();
 	}
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index 853dce4..1156591 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_DWARF2OUT_H 1
 
 #include "dwarf2.h"	/* ??? Remove this once only used by dwarf2foo.c.  */
+#include "wide-int.h"
 
 typedef struct die_struct *dw_die_ref;
 typedef const struct die_struct *const_dw_die_ref;
@@ -143,6 +144,7 @@ enum dw_val_class
   dw_val_class_const,
   dw_val_class_unsigned_const,
   dw_val_class_const_double,
+  dw_val_class_wide_int,
   dw_val_class_vec,
   dw_val_class_flag,
   dw_val_class_die_ref,
@@ -181,6 +183,7 @@ typedef struct GTY(()) dw_val_struct {
       HOST_WIDE_INT GTY ((default)) val_int;
       unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
       double_int GTY ((tag ("dw_val_class_const_double"))) val_double;
+      wide_int GTY ((tag ("dw_val_class_wide_int"))) val_wide;
       dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
       struct dw_val_die_union
 	{
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index bd6fc26..5b809d9 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -128,6 +128,9 @@ rtx cc0_rtx;
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
      htab_t const_int_htab;
 
+static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
+     htab_t const_wide_int_htab;
+
 /* A hash table storing memory attribute structures.  */
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct mem_attrs)))
      htab_t mem_attrs_htab;
@@ -153,6 +156,11 @@ static void set_used_decls (tree);
 static void mark_label_nuses (rtx);
 static hashval_t const_int_htab_hash (const void *);
 static int const_int_htab_eq (const void *, const void *);
+#if TARGET_SUPPORTS_WIDE_INT
+static hashval_t const_wide_int_htab_hash (const void *);
+static int const_wide_int_htab_eq (const void *, const void *);
+static rtx lookup_const_wide_int (rtx);
+#endif
 static hashval_t const_double_htab_hash (const void *);
 static int const_double_htab_eq (const void *, const void *);
 static rtx lookup_const_double (rtx);
@@ -189,6 +197,43 @@ const_int_htab_eq (const void *x, const void *y)
   return (INTVAL ((const_rtx) x) == *((const HOST_WIDE_INT *) y));
 }
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns a hash code for X (which is a really a CONST_WIDE_INT).  */
+
+static hashval_t
+const_wide_int_htab_hash (const void *x)
+{
+  int i;
+  HOST_WIDE_INT hash = 0;
+  const_rtx xr = (const_rtx) x;
+
+  for (i = 0; i < CONST_WIDE_INT_NUNITS (xr); i++)
+    hash += CONST_WIDE_INT_ELT (xr, i);
+
+  return (hashval_t) hash;
+}
+
+/* Returns nonzero if the value represented by X (which is really a
+   CONST_WIDE_INT) is the same as that given by Y (which is really a
+   CONST_WIDE_INT).  */
+
+static int
+const_wide_int_htab_eq (const void *x, const void *y)
+{
+  int i;
+  const_rtx xr = (const_rtx)x;
+  const_rtx yr = (const_rtx)y;
+  if (CONST_WIDE_INT_NUNITS (xr) != CONST_WIDE_INT_NUNITS (yr))
+    return 0;
+
+  for (i = 0; i < CONST_WIDE_INT_NUNITS (xr); i++)
+    if (CONST_WIDE_INT_ELT (xr, i) != CONST_WIDE_INT_ELT (yr, i))
+      return 0;
+  
+  return 1;
+}
+#endif
+
 /* Returns a hash code for X (which is really a CONST_DOUBLE).  */
 static hashval_t
 const_double_htab_hash (const void *x)
@@ -196,7 +241,7 @@ const_double_htab_hash (const void *x)
   const_rtx const value = (const_rtx) x;
   hashval_t h;
 
-  if (GET_MODE (value) == VOIDmode)
+  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (value) == VOIDmode)
     h = CONST_DOUBLE_LOW (value) ^ CONST_DOUBLE_HIGH (value);
   else
     {
@@ -216,7 +261,7 @@ const_double_htab_eq (const void *x, const void *y)
 
   if (GET_MODE (a) != GET_MODE (b))
     return 0;
-  if (GET_MODE (a) == VOIDmode)
+  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (a) == VOIDmode)
     return (CONST_DOUBLE_LOW (a) == CONST_DOUBLE_LOW (b)
 	    && CONST_DOUBLE_HIGH (a) == CONST_DOUBLE_HIGH (b));
   else
@@ -482,6 +527,7 @@ const_fixed_from_fixed_value (FIXED_VALUE_TYPE value, enum machine_mode mode)
   return lookup_const_fixed (fixed);
 }
 
+#if TARGET_SUPPORTS_WIDE_INT == 0
 /* Constructs double_int from rtx CST.  */
 
 double_int
@@ -501,17 +547,58 @@ rtx_to_double_int (const_rtx cst)
   
   return r;
 }
+#endif
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Determine whether WIDE_INT, already exists in the hash table.  If
+   so, return its counterpart; otherwise add it to the hash table and
+   return it.  */
 
-/* Return a CONST_DOUBLE or CONST_INT for a value specified as
-   a double_int.  */
+static rtx
+lookup_const_wide_int (rtx wint)
+{
+  void **slot = htab_find_slot (const_wide_int_htab, wint, INSERT);
+  if (*slot == 0)
+    *slot = wint;
 
+  return (rtx) *slot;
+}
+#endif
+
+/* V contains a wide_int.  A CONST_INT or CONST_WIDE_INT (if
+   TARGET_SUPPORTS_WIDE_INT is defined) or CONST_DOUBLE if
+   TARGET_SUPPORTS_WIDE_INT is not defined is produced based on the
+   number of HOST_WIDE_INTs that are necessary to represent the value
+   in compact form.  */
 rtx
-immed_double_int_const (double_int i, enum machine_mode mode)
+immed_wide_int_const (const wide_int &v, enum machine_mode mode)
 {
-  return immed_double_const (i.low, i.high, mode);
+  unsigned int len = v.get_len ();
+
+  if (len < 2)
+    return gen_int_mode (v.elt (0), mode);
+
+#if TARGET_SUPPORTS_WIDE_INT
+  {
+    rtx value = const_wide_int_alloc (len);
+    unsigned int i;
+
+    /* It is so tempting to just put the mode in here.  Must control
+       myself ... */
+    PUT_MODE (value, VOIDmode);
+    HWI_PUT_NUM_ELEM (CONST_WIDE_INT_VEC (value), len);
+
+    for (i = 0; i < len; i++)
+      CONST_WIDE_INT_ELT (value, i) = v.elt (i);
+
+    return lookup_const_wide_int (value);
+  }
+#else
+  return immed_double_const (v.elt (0), v.elt (1), mode);
+#endif
 }
 
+#if TARGET_SUPPORTS_WIDE_INT == 0
 /* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair
    of ints: I0 is the low-order word and I1 is the high-order word.
    For values that are larger than HOST_BITS_PER_DOUBLE_INT, the
@@ -563,6 +650,7 @@ immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode)
 
   return lookup_const_double (value);
 }
+#endif
 
 rtx
 gen_rtx_REG (enum machine_mode mode, unsigned int regno)
@@ -5575,11 +5663,15 @@ init_emit_once (void)
   enum machine_mode mode;
   enum machine_mode double_mode;
 
-  /* Initialize the CONST_INT, CONST_DOUBLE, CONST_FIXED, and memory attribute
-     hash tables.  */
+  /* Initialize the CONST_INT, CONST_WIDE_INT, CONST_DOUBLE,
+     CONST_FIXED, and memory attribute hash tables.  */
   const_int_htab = htab_create_ggc (37, const_int_htab_hash,
 				    const_int_htab_eq, NULL);
 
+#if TARGET_SUPPORTS_WIDE_INT
+  const_wide_int_htab = htab_create_ggc (37, const_wide_int_htab_hash,
+					 const_wide_int_htab_eq, NULL);
+#endif
   const_double_htab = htab_create_ggc (37, const_double_htab_hash,
 				       const_double_htab_eq, NULL);
 
diff --git a/gcc/explow.c b/gcc/explow.c
index 6109832..86f71cd 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -97,38 +97,8 @@ plus_constant (enum machine_mode mode, rtx x, HOST_WIDE_INT c)
 
   switch (code)
     {
-    case CONST_INT:
-      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
-	{
-	  double_int di_x = double_int::from_shwi (INTVAL (x));
-	  double_int di_c = double_int::from_shwi (c);
-
-	  bool overflow;
-	  double_int v = di_x.add_with_sign (di_c, false, &overflow);
-	  if (overflow)
-	    gcc_unreachable ();
-
-	  return immed_double_int_const (v, VOIDmode);
-	}
-
-      return GEN_INT (INTVAL (x) + c);
-
-    case CONST_DOUBLE:
-      {
-	double_int di_x = double_int::from_pair (CONST_DOUBLE_HIGH (x),
-						 CONST_DOUBLE_LOW (x));
-	double_int di_c = double_int::from_shwi (c);
-
-	bool overflow;
-	double_int v = di_x.add_with_sign (di_c, false, &overflow);
-	if (overflow)
-	  /* Sorry, we have no way to represent overflows this wide.
-	     To fix, add constant support wider than CONST_DOUBLE.  */
-	  gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT);
-
-	return immed_double_int_const (v, VOIDmode);
-      }
-
+    CASE_CONST_SCALAR_INT:
+      return immed_wide_int_const (wide_int::from_rtx (x, mode) + c, mode);
     case MEM:
       /* If this is a reference to the constant pool, try replacing it with
 	 a reference to a new constant.  If the resulting address isn't
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 767834e..7434d0e 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -60,7 +60,6 @@ static rtx extract_fixed_bit_field (enum machine_mode, rtx,
 				    unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT, rtx, int, bool);
-static rtx mask_rtx (enum machine_mode, int, int, int);
 static rtx lshift_value (enum machine_mode, rtx, int, int);
 static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT, int);
@@ -68,6 +67,19 @@ static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
 static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 
+/* Return a constant integer (CONST_INT or CONST_WIDE_INT) mask value
+   of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
+   complement of that if COMPLEMENT.  The mask is truncated if
+   necessary to the width of mode MODE.  The mask is zero-extended if
+   BITSIZE+BITPOS is too small for MODE.  */
+
+static inline rtx 
+mask_rtx (enum machine_mode mode, int bitpos, int bitsize, bool complement)
+{
+  return immed_wide_int_const 
+    (wide_int::shifted_mask (bitpos, bitsize, complement, mode), mode);
+}
+
 /* Test whether a value is zero of a power of two.  */
 #define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
 
@@ -1961,39 +1973,16 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
   return expand_shift (RSHIFT_EXPR, mode, op0,
 		       GET_MODE_BITSIZE (mode) - bitsize, target, 0);
 }
-\f
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) mask value
-   of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
-   complement of that if COMPLEMENT.  The mask is truncated if
-   necessary to the width of mode MODE.  The mask is zero-extended if
-   BITSIZE+BITPOS is too small for MODE.  */
-
-static rtx
-mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
-{
-  double_int mask;
-
-  mask = double_int::mask (bitsize);
-  mask = mask.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
-  if (complement)
-    mask = ~mask;
-
-  return immed_double_int_const (mask, mode);
-}
-
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
-   VALUE truncated to BITSIZE bits and then shifted left BITPOS bits.  */
+/* Return a constant integer (CONST_INT or CONST_WIDE_INT) rtx with the value
+   VALUE truncated to BITSIZE bits and then shifted left BITPOS bits.   */
 
 static rtx
 lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
 {
-  double_int val;
-  
-  val = double_int::from_uhwi (INTVAL (value)).zext (bitsize);
-  val = val.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
-  return immed_double_int_const (val, mode);
+  return 
+    immed_wide_int_const (wide_int::from_rtx (value, mode)
+			  .zext (bitsize)
+			  .lshift (bitpos, wide_int::NONE), mode);
 }
 \f
 /* Extract a bit field that is split across two words
@@ -3199,34 +3188,41 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 	 only if the constant value exactly fits in an `unsigned int' without
 	 any truncation.  This means that multiplying by negative values does
 	 not work; results are off by 2^32 on a 32 bit machine.  */
-
       if (CONST_INT_P (scalar_op1))
 	{
 	  coeff = INTVAL (scalar_op1);
 	  is_neg = coeff < 0;
 	}
+#if TARGET_SUPPORTS_WIDE_INT
+      else if (CONST_WIDE_INT_P (scalar_op1))
+#else
       else if (CONST_DOUBLE_AS_INT_P (scalar_op1))
+#endif
 	{
-	  /* If we are multiplying in DImode, it may still be a win
-	     to try to work with shifts and adds.  */
-	  if (CONST_DOUBLE_HIGH (scalar_op1) == 0
-	      && CONST_DOUBLE_LOW (scalar_op1) > 0)
+	  int p = GET_MODE_PRECISION (mode);
+	  wide_int val = wide_int::from_rtx (scalar_op1, mode);
+	  int shift = val.exact_log2 (); 
+	  /* Perfect power of 2.  */
+	  is_neg = false;
+	  if (shift > 0)
 	    {
-	      coeff = CONST_DOUBLE_LOW (scalar_op1);
-	      is_neg = false;
+	      /* Do the shift count trucation against the bitsize, not
+		 the precision.  See the comment above
+		 wide-int.c:trunc_shift for details.  */
+	      if (SHIFT_COUNT_TRUNCATED)
+		shift &= GET_MODE_BITSIZE (mode) - 1;
+	      /* We could consider adding just a move of 0 to target
+		 if the shift >= p  */
+	      if (shift < p)
+		return expand_shift (LSHIFT_EXPR, mode, op0, 
+				     shift, target, unsignedp);
+	      /* Any positive number that fits in a word.  */
+	      coeff = CONST_WIDE_INT_ELT (scalar_op1, 0);
 	    }
-	  else if (CONST_DOUBLE_LOW (scalar_op1) == 0)
+	  else if (val.sign_mask () == 0)
 	    {
-	      coeff = CONST_DOUBLE_HIGH (scalar_op1);
-	      if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
-		{
-		  int shift = floor_log2 (coeff) + HOST_BITS_PER_WIDE_INT;
-		  if (shift < HOST_BITS_PER_DOUBLE_INT - 1
-		      || mode_bitsize <= HOST_BITS_PER_DOUBLE_INT)
-		    return expand_shift (LSHIFT_EXPR, mode, op0,
-					 shift, target, unsignedp);
-		}
-	      goto skip_synth;
+	      /* Any positive number that fits in a word.  */
+	      coeff = CONST_WIDE_INT_ELT (scalar_op1, 0);
 	    }
 	  else
 	    goto skip_synth;
@@ -3716,9 +3712,10 @@ expmed_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
 static rtx
 expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 {
-  unsigned HOST_WIDE_INT masklow, maskhigh;
   rtx result, temp, shift, label;
   int logd;
+  wide_int mask;
+  int prec = GET_MODE_PRECISION (mode);
 
   logd = floor_log2 (d);
   result = gen_reg_rtx (mode);
@@ -3731,8 +3728,8 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 				      mode, 0, -1);
       if (signmask)
 	{
+	  HOST_WIDE_INT masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
 	  signmask = force_reg (mode, signmask);
-	  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
 	  shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
 
 	  /* Use the rtx_cost of a LSHIFTRT instruction to determine
@@ -3777,19 +3774,11 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
      modulus.  By including the signbit in the operation, many targets
      can avoid an explicit compare operation in the following comparison
      against zero.  */
-
-  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
-  if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
-    {
-      masklow |= (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1);
-      maskhigh = -1;
-    }
-  else
-    maskhigh = (HOST_WIDE_INT) -1
-		 << (GET_MODE_BITSIZE (mode) - HOST_BITS_PER_WIDE_INT - 1);
+  mask = wide_int::mask (logd, false, mode);
+  mask = mask.set_bit (prec - 1);
 
   temp = expand_binop (mode, and_optab, op0,
-		       immed_double_const (masklow, maskhigh, mode),
+		       immed_wide_int_const (mask, mode),
 		       result, 1, OPTAB_LIB_WIDEN);
   if (temp != result)
     emit_move_insn (result, temp);
@@ -3799,10 +3788,10 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 
   temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
 		       0, OPTAB_LIB_WIDEN);
-  masklow = (HOST_WIDE_INT) -1 << logd;
-  maskhigh = -1;
+
+  mask = wide_int::mask (logd, true, mode); 
   temp = expand_binop (mode, ior_optab, temp,
-		       immed_double_const (masklow, maskhigh, mode),
+		       immed_wide_int_const (mask, mode),
 		       result, 1, OPTAB_LIB_WIDEN);
   temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
 		       0, OPTAB_LIB_WIDEN);
@@ -5056,8 +5045,12 @@ make_tree (tree type, rtx x)
 	return t;
       }
 
+    case CONST_WIDE_INT:
+      t = wide_int_to_tree (type, wide_int::from_rtx (x, TYPE_MODE (type)));
+      return t;
+
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	t = build_int_cst_wide (type,
 				CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
       else
diff --git a/gcc/expr.c b/gcc/expr.c
index 1adea93..6677cb0 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -719,23 +719,23 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
   if (mode == oldmode)
     return x;
 
-  /* There is one case that we must handle specially: If we are converting
-     a CONST_INT into a mode whose size is twice HOST_BITS_PER_WIDE_INT and
-     we are to interpret the constant as unsigned, gen_lowpart will do
-     the wrong if the constant appears negative.  What we want to do is
-     make the high-order word of the constant zero, not all ones.  */
+  /* There is one case that we must handle specially: If we are
+     converting a CONST_INT into a mode whose size is larger than
+     HOST_BITS_PER_WIDE_INT and we are to interpret the constant as
+     unsigned, gen_lowpart will do the wrong if the constant appears
+     negative.  What we want to do is make the high-order word of the
+     constant zero, not all ones.  */
 
   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
-      && GET_MODE_BITSIZE (mode) == HOST_BITS_PER_DOUBLE_INT
+      && GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT
       && CONST_INT_P (x) && INTVAL (x) < 0)
     {
-      double_int val = double_int::from_uhwi (INTVAL (x));
-
+      HOST_WIDE_INT val = INTVAL (x);
       /* We need to zero extend VAL.  */
       if (oldmode != VOIDmode)
-	val = val.zext (GET_MODE_BITSIZE (oldmode));
+	val &= GET_MODE_PRECISION (oldmode) - 1;
 
-      return immed_double_int_const (val, mode);
+      return immed_wide_int_const (wide_int::from_uhwi (val, mode), mode);
     }
 
   /* We can do this with a gen_lowpart if both desired and current modes
@@ -747,7 +747,11 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
        && GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT)
       || (GET_MODE_CLASS (mode) == MODE_INT
 	  && GET_MODE_CLASS (oldmode) == MODE_INT
-	  && (CONST_DOUBLE_AS_INT_P (x) 
+#if TARGET_SUPPORTS_WIDE_INT
+	  && (CONST_WIDE_INT_P (x)
+#else
+ 	  && (CONST_DOUBLE_AS_INT_P (x)
+#endif
 	      || (GET_MODE_PRECISION (mode) <= GET_MODE_PRECISION (oldmode)
 		  && ((MEM_P (x) && ! MEM_VOLATILE_P (x)
 		       && direct_load[(int) mode])
@@ -1752,6 +1756,7 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
 	    {
 	      rtx first, second;
 
+	      /* TODO: const_wide_int can have sizes other than this...  */
 	      gcc_assert (2 * len == ssize);
 	      split_double (src, &first, &second);
 	      if (i)
@@ -5180,10 +5185,10 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 			       &alt_rtl);
     }
 
-  /* If TEMP is a VOIDmode constant and the mode of the type of EXP is not
-     the same as that of TARGET, adjust the constant.  This is needed, for
-     example, in case it is a CONST_DOUBLE and we want only a word-sized
-     value.  */
+  /* If TEMP is a VOIDmode constant and the mode of the type of EXP is
+     not the same as that of TARGET, adjust the constant.  This is
+     needed, for example, in case it is a CONST_DOUBLE or
+     CONST_WIDE_INT and we want only a word-sized value.  */
   if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode
       && TREE_CODE (exp) != ERROR_MARK
       && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
@@ -7711,11 +7716,12 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
 
   /* All elts simple constants => refer to a constant in memory.  But
      if this is a non-BLKmode mode, let it store a field at a time
-     since that should make a CONST_INT or CONST_DOUBLE when we
-     fold.  Likewise, if we have a target we can use, it is best to
-     store directly into the target unless the type is large enough
-     that memcpy will be used.  If we are making an initializer and
-     all operands are constant, put it in memory as well.
+     since that should make a CONST_INT, CONST_WIDE_INT or
+     CONST_DOUBLE when we fold.  Likewise, if we have a target we can
+     use, it is best to store directly into the target unless the type
+     is large enough that memcpy will be used.  If we are making an
+     initializer and all operands are constant, put it in memory as
+     well.
 
      FIXME: Avoid trying to fill vector constructors piece-meal.
      Output them with output_constant_def below unless we're sure
@@ -8207,17 +8213,18 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 	      && TREE_CONSTANT (treeop1))
 	    {
 	      rtx constant_part;
+	      HOST_WIDE_INT wc;
+	      enum machine_mode wmode = TYPE_MODE (TREE_TYPE (treeop1));
 
 	      op1 = expand_expr (treeop1, subtarget, VOIDmode,
 				 EXPAND_SUM);
-	      /* Use immed_double_const to ensure that the constant is
+	      /* Use wide_int::from_shwi to ensure that the constant is
 		 truncated according to the mode of OP1, then sign extended
 		 to a HOST_WIDE_INT.  Using the constant directly can result
 		 in non-canonical RTL in a 64x32 cross compile.  */
-	      constant_part
-		= immed_double_const (TREE_INT_CST_LOW (treeop0),
-				      (HOST_WIDE_INT) 0,
-				      TYPE_MODE (TREE_TYPE (treeop1)));
+	      wc = TREE_INT_CST_LOW (treeop0);
+	      constant_part 
+		= immed_wide_int_const (wide_int::from_shwi (wc, wmode), wmode);
 	      op1 = plus_constant (mode, op1, INTVAL (constant_part));
 	      if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
 		op1 = force_operand (op1, target);
@@ -8229,7 +8236,8 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 		   && TREE_CONSTANT (treeop0))
 	    {
 	      rtx constant_part;
-
+	      HOST_WIDE_INT wc;
+	      enum machine_mode wmode = TYPE_MODE (TREE_TYPE (treeop0));
 	      op0 = expand_expr (treeop0, subtarget, VOIDmode,
 				 (modifier == EXPAND_INITIALIZER
 				 ? EXPAND_INITIALIZER : EXPAND_SUM));
@@ -8243,14 +8251,13 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 		    return simplify_gen_binary (PLUS, mode, op0, op1);
 		  goto binop2;
 		}
-	      /* Use immed_double_const to ensure that the constant is
+	      /* Use wide_int::from_shwi to ensure that the constant is
 		 truncated according to the mode of OP1, then sign extended
 		 to a HOST_WIDE_INT.  Using the constant directly can result
 		 in non-canonical RTL in a 64x32 cross compile.  */
-	      constant_part
-		= immed_double_const (TREE_INT_CST_LOW (treeop1),
-				      (HOST_WIDE_INT) 0,
-				      TYPE_MODE (TREE_TYPE (treeop0)));
+	      wc = TREE_INT_CST_LOW (treeop1);
+	      constant_part 
+		= immed_wide_int_const (wide_int::from_shwi (wc, wmode), wmode);
 	      op0 = plus_constant (mode, op0, INTVAL (constant_part));
 	      if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
 		op0 = force_operand (op0, target);
@@ -8752,10 +8759,13 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 	 for unsigned bitfield expand this as XOR with a proper constant
 	 instead.  */
       if (reduce_bit_field && TYPE_UNSIGNED (type))
-	temp = expand_binop (mode, xor_optab, op0,
-			     immed_double_int_const
-			       (double_int::mask (TYPE_PRECISION (type)), mode),
-			     target, 1, OPTAB_LIB_WIDEN);
+	{
+	  wide_int mask = wide_int::mask (TYPE_PRECISION (type), false, mode);
+
+	  temp = expand_binop (mode, xor_optab, op0,
+			       immed_wide_int_const (mask, mode),
+			       target, 1, OPTAB_LIB_WIDEN);
+	}
       else
 	temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
       gcc_assert (temp);
@@ -9335,9 +9345,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return decl_rtl;
 
     case INTEGER_CST:
-      temp = immed_double_const (TREE_INT_CST_LOW (exp),
-				 TREE_INT_CST_HIGH (exp), mode);
-
+      temp = immed_wide_int_const (wide_int::from_tree (exp), 
+				   TYPE_MODE (TREE_TYPE (exp)));
       return temp;
 
     case VECTOR_CST:
@@ -9568,8 +9577,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 	op0 = memory_address_addr_space (address_mode, op0, as);
 	if (!integer_zerop (TREE_OPERAND (exp, 1)))
 	  {
-	    rtx off
-	      = immed_double_int_const (mem_ref_offset (exp), address_mode);
+	    wide_int wi = wide_int::from_double_int
+	      (address_mode, mem_ref_offset (exp));
+	    rtx off = immed_wide_int_const (wi, address_mode);
 	    op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
 	  }
 	op0 = memory_address_addr_space (mode, op0, as);
@@ -10441,9 +10451,10 @@ reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
     }
   else if (TYPE_UNSIGNED (type))
     {
-      rtx mask = immed_double_int_const (double_int::mask (prec),
-					 GET_MODE (exp));
-      return expand_and (GET_MODE (exp), exp, mask, target);
+      enum machine_mode mode = GET_MODE (exp);
+      rtx mask = immed_wide_int_const 
+	(wide_int::mask (prec, false, mode), mode);
+      return expand_and (mode, exp, mask, target);
     }
   else
     {
@@ -11007,8 +11018,9 @@ const_vector_from_tree (tree exp)
 	RTVEC_ELT (v, i) = CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (elt),
 							 inner);
       else
-	RTVEC_ELT (v, i) = immed_double_int_const (tree_to_double_int (elt),
-						   inner);
+	RTVEC_ELT (v, i) 
+	  = immed_wide_int_const (wide_int::from_tree (elt),
+				  TYPE_MODE (TREE_TYPE (elt)));
     }
 
   return gen_rtx_CONST_VECTOR (mode, v);
diff --git a/gcc/final.c b/gcc/final.c
index 0839340..e9d80bd 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -3728,8 +3728,16 @@ output_addr_const (FILE *file, rtx x)
       output_addr_const (file, XEXP (x, 0));
       break;
 
+    case CONST_WIDE_INT:
+      /* This should be ok for a while.  */
+      gcc_assert (CONST_WIDE_INT_NUNITS (x) == 2);
+      fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
+	       (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, 1),
+	       (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, 0));
+      break;
+
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
+      if (CONST_DOUBLE_AS_INT_P (x))
 	{
 	  /* We can use %d if the number is one word and positive.  */
 	  if (CONST_DOUBLE_HIGH (x))
diff --git a/gcc/genemit.c b/gcc/genemit.c
index eefe497..44ce2d2 100644
--- a/gcc/genemit.c
+++ b/gcc/genemit.c
@@ -205,6 +205,7 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used)
 
     case CONST_DOUBLE:
     case CONST_FIXED:
+    case CONST_WIDE_INT:
       /* These shouldn't be written in MD files.  Instead, the appropriate
 	 routines in varasm.c should be called.  */
       gcc_unreachable ();
diff --git a/gcc/gengenrtl.c b/gcc/gengenrtl.c
index 58d3142..7a89039 100644
--- a/gcc/gengenrtl.c
+++ b/gcc/gengenrtl.c
@@ -143,6 +143,7 @@ static int
 excluded_rtx (int idx)
 {
   return ((strcmp (defs[idx].enumname, "CONST_DOUBLE") == 0)
+	  || (strcmp (defs[idx].enumname, "CONST_WIDE_INT") == 0)
 	  || (strcmp (defs[idx].enumname, "CONST_FIXED") == 0));
 }
 
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 2135676..12f533a 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -5448,6 +5448,7 @@ main (int argc, char **argv)
       POS_HERE (do_scalar_typedef ("REAL_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("FIXED_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("double_int", &pos));
+      POS_HERE (do_scalar_typedef ("wide_int", &pos));
       POS_HERE (do_scalar_typedef ("uint64_t", &pos));
       POS_HERE (do_scalar_typedef ("uint8", &pos));
       POS_HERE (do_scalar_typedef ("uintptr_t", &pos));
diff --git a/gcc/genpreds.c b/gcc/genpreds.c
index de91349..14fa326 100644
--- a/gcc/genpreds.c
+++ b/gcc/genpreds.c
@@ -613,7 +613,7 @@ write_one_predicate_function (struct pred_data *p)
   add_mode_tests (p);
 
   /* A normal predicate can legitimately not look at enum machine_mode
-     if it accepts only CONST_INTs and/or CONST_DOUBLEs.  */
+     if it accepts only CONST_INTs and/or CONST_WIDE_INT and/or CONST_DOUBLEs.  */
   printf ("int\n%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n{\n",
 	  p->name);
   write_predicate_stmts (p->exp);
@@ -810,8 +810,11 @@ add_constraint (const char *name, const char *regclass,
   if (is_const_int || is_const_dbl)
     {
       enum rtx_code appropriate_code
+#if TARGET_SUPPORTS_WIDE_INT
+	= is_const_int ? CONST_INT : CONST_WIDE_INT;
+#else
 	= is_const_int ? CONST_INT : CONST_DOUBLE;
-
+#endif
       /* Consider relaxing this requirement in the future.  */
       if (regclass
 	  || GET_CODE (exp) != AND
@@ -1075,12 +1078,17 @@ write_tm_constrs_h (void)
 	if (needs_ival)
 	  puts ("  if (CONST_INT_P (op))\n"
 		"    ival = INTVAL (op);");
+#if TARGET_SUPPORTS_WIDE_INT
+	if (needs_lval || needs_hval)
+	  error ("you can't use lval or hval");
+#else
 	if (needs_hval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)"
 		"    hval = CONST_DOUBLE_HIGH (op);");
 	if (needs_lval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)"
 		"    lval = CONST_DOUBLE_LOW (op);");
+#endif
 	if (needs_rval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode != VOIDmode)"
 		"    rval = CONST_DOUBLE_REAL_VALUE (op);");
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index 44443e2..eb7fb71 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -1671,7 +1671,13 @@ static const struct std_pred_table std_preds[] = {
   {"scratch_operand", false, false, {SCRATCH, REG}},
   {"immediate_operand", false, true, {UNKNOWN}},
   {"const_int_operand", false, false, {CONST_INT}},
+#if TARGET_SUPPORTS_WIDE_INT
+  {"const_wide_int_operand", false, false, {CONST_WIDE_INT}},
+  {"const_scalar_int_operand", false, false, {CONST_INT, CONST_WIDE_INT}},
+  {"const_double_operand", false, false, {CONST_DOUBLE}},
+#else
   {"const_double_operand", false, false, {CONST_INT, CONST_DOUBLE}},
+#endif
   {"nonimmediate_operand", false, false, {SUBREG, REG, MEM}},
   {"nonmemory_operand", false, true, {SUBREG, REG}},
   {"push_operand", false, false, {MEM}},
diff --git a/gcc/ggc-zone.c b/gcc/ggc-zone.c
index 2cf7167..500f736 100644
--- a/gcc/ggc-zone.c
+++ b/gcc/ggc-zone.c
@@ -1373,6 +1373,9 @@ ggc_alloc_typed_stat (enum gt_types_enum gte, size_t size
     case gt_ggc_e_9rtvec_def:
       return ggc_internal_alloc_zone_pass_stat (size, &rtl_zone);
 
+    case gt_ggc_e_10hwivec_def:
+      return ggc_internal_alloc_zone_pass_stat (size, &rtl_zone);
+
     default:
       return ggc_internal_alloc_zone_pass_stat (size, &main_zone);
     }
diff --git a/gcc/ggc.h b/gcc/ggc.h
index 5f25a58..7ca4cc7 100644
--- a/gcc/ggc.h
+++ b/gcc/ggc.h
@@ -271,6 +271,11 @@ extern struct alloc_zone tree_id_zone;
 			    + ((NELT) - 1) * sizeof (rtx),		\
 			    &rtl_zone)
 
+#define ggc_alloc_hwivec_sized(NELT)                                      \
+  ggc_alloc_zone_hwivec_def (sizeof (struct hwivec_def)			\
+			    + ((NELT) - 1) * sizeof (HOST_WIDE_INT),	\
+			    &rtl_zone)
+
 #if defined (GGC_ZONE) && !defined (GENERATOR_FILE)
 
 /* Allocate an object into the specified allocation zone.  */
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 8a6c6a3..6345dd1 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -838,7 +838,8 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
   if (CONSTANT_P (op1) || shift_mask >= BITS_PER_WORD)
     {
       carries = outof_input;
-      tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
+      tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD,
+						       op1_mode), op1_mode);
       tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
 				   0, true, methods);
     }
@@ -853,13 +854,14 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
 			      outof_input, const1_rtx, 0, unsignedp, methods);
       if (shift_mask == BITS_PER_WORD - 1)
 	{
-	  tmp = immed_double_const (-1, -1, op1_mode);
+	  tmp = immed_wide_int_const (wide_int::minus_one (op1_mode), op1_mode);
 	  tmp = simplify_expand_binop (op1_mode, xor_optab, op1, tmp,
 				       0, true, methods);
 	}
       else
 	{
-	  tmp = immed_double_const (BITS_PER_WORD - 1, 0, op1_mode);
+	  tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD - 1,
+							   op1_mode), op1_mode);
 	  tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
 				       0, true, methods);
 	}
@@ -1022,7 +1024,7 @@ expand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
      is true when the effective shift value is less than BITS_PER_WORD.
      Set SUPERWORD_OP1 to the shift count that should be used to shift
      OUTOF_INPUT into INTO_TARGET when the condition is false.  */
-  tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
+  tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD, op1_mode), op1_mode);
   if (!CONSTANT_P (op1) && shift_mask == BITS_PER_WORD - 1)
     {
       /* Set CMP1 to OP1 & BITS_PER_WORD.  The result is zero iff OP1
@@ -2872,7 +2874,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
   const struct real_format *fmt;
   int bitpos, word, nwords, i;
   enum machine_mode imode;
-  double_int mask;
+  wide_int mask;
   rtx temp, insns;
 
   /* The format has to have a simple sign bit.  */
@@ -2908,7 +2910,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
       nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
     }
 
-  mask = double_int_zero.set_bit (bitpos);
+  mask = wide_int::set_bit_in_zero (bitpos, imode);
   if (code == ABS)
     mask = ~mask;
 
@@ -2930,7 +2932,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
 	    {
 	      temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
 				   op0_piece,
-				   immed_double_int_const (mask, imode),
+				   immed_wide_int_const (mask, imode),
 				   targ_piece, 1, OPTAB_LIB_WIDEN);
 	      if (temp != targ_piece)
 		emit_move_insn (targ_piece, temp);
@@ -2948,7 +2950,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
     {
       temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
 			   gen_lowpart (imode, op0),
-			   immed_double_int_const (mask, imode),
+			   immed_wide_int_const (mask, imode),
 		           gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
       target = lowpart_subreg_maybe_copy (mode, temp, imode);
 
@@ -3547,7 +3549,7 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
     }
   else
     {
-      double_int mask;
+      wide_int mask;
 
       if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
 	{
@@ -3569,10 +3571,9 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 	  op1 = operand_subword_force (op1, word, mode);
 	}
 
-      mask = double_int_zero.set_bit (bitpos);
-
+      mask = wide_int::set_bit_in_zero (bitpos, imode);
       sign = expand_binop (imode, and_optab, op1,
-			   immed_double_int_const (mask, imode),
+			   immed_wide_int_const (mask, imode),
 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
 
@@ -3616,7 +3617,7 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 		     int bitpos, bool op0_is_abs)
 {
   enum machine_mode imode;
-  double_int mask;
+  wide_int mask, nmask;
   int word, nwords, i;
   rtx temp, insns;
 
@@ -3640,7 +3641,7 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
       nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
     }
 
-  mask = double_int_zero.set_bit (bitpos);
+  mask = wide_int::set_bit_in_zero (bitpos, imode);
 
   if (target == 0
       || target == op0
@@ -3660,14 +3661,16 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 	  if (i == word)
 	    {
 	      if (!op0_is_abs)
-		op0_piece
-		  = expand_binop (imode, and_optab, op0_piece,
-				  immed_double_int_const (~mask, imode),
-				  NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
+		{
+		  nmask = ~mask;
+  		  op0_piece
+		    = expand_binop (imode, and_optab, op0_piece,
+				    immed_wide_int_const (nmask, imode),
+				    NULL_RTX, 1, OPTAB_LIB_WIDEN);
+		}
 	      op1 = expand_binop (imode, and_optab,
 				  operand_subword_force (op1, i, mode),
-				  immed_double_int_const (mask, imode),
+				  immed_wide_int_const (mask, imode),
 				  NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
 	      temp = expand_binop (imode, ior_optab, op0_piece, op1,
@@ -3687,15 +3690,17 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
   else
     {
       op1 = expand_binop (imode, and_optab, gen_lowpart (imode, op1),
-		          immed_double_int_const (mask, imode),
+		          immed_wide_int_const (mask, imode),
 		          NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
       op0 = gen_lowpart (imode, op0);
       if (!op0_is_abs)
-	op0 = expand_binop (imode, and_optab, op0,
-			    immed_double_int_const (~mask, imode),
-			    NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
+	{
+	  nmask = ~mask;
+	  op0 = expand_binop (imode, and_optab, op0,
+			      immed_wide_int_const (nmask, imode),
+			      NULL_RTX, 1, OPTAB_LIB_WIDEN);
+	}
       temp = expand_binop (imode, ior_optab, op0, op1,
 			   gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
       target = lowpart_subreg_maybe_copy (mode, temp, imode);
diff --git a/gcc/postreload.c b/gcc/postreload.c
index 38be0ab..a0ad622 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -286,27 +286,25 @@ reload_cse_simplify_set (rtx set, rtx insn)
 #ifdef LOAD_EXTEND_OP
 	  if (extend_op != UNKNOWN)
 	    {
-	      HOST_WIDE_INT this_val;
+	      wide_int result;
 
-	      /* ??? I'm lazy and don't wish to handle CONST_DOUBLE.  Other
-		 constants, such as SYMBOL_REF, cannot be extended.  */
-	      if (!CONST_INT_P (this_rtx))
+	      if (!CONST_SCALAR_INT_P (this_rtx))
 		continue;
 
-	      this_val = INTVAL (this_rtx);
 	      switch (extend_op)
 		{
 		case ZERO_EXTEND:
-		  this_val &= GET_MODE_MASK (GET_MODE (src));
+		  result = (wide_int::from_rtx (this_rtx, GET_MODE (src))
+			    .zext (word_mode));
 		  break;
 		case SIGN_EXTEND:
-		  /* ??? In theory we're already extended.  */
-		  if (this_val == trunc_int_for_mode (this_val, GET_MODE (src)))
-		    break;
+		  result = (wide_int::from_rtx (this_rtx, GET_MODE (src))
+			    .sext (word_mode));
+		  break;
 		default:
 		  gcc_unreachable ();
 		}
-	      this_rtx = GEN_INT (this_val);
+	      this_rtx = immed_wide_int_const (result, GET_MODE (src));
 	    }
 #endif
 	  this_cost = set_src_cost (this_rtx, speed);
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index c2a04a8..c6c3a40 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -634,6 +634,12 @@ print_rtx (const_rtx in_rtx)
 	  fprintf (outfile, " [%s]", s);
 	}
       break;
+
+    case CONST_WIDE_INT:
+      if (! flag_simple)
+	fprintf (outfile, " ");
+      hwivec_output_hex (outfile, CONST_WIDE_INT_VEC (in_rtx));
+      break;
 #endif
 
     case CODE_LABEL:
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 30c2fb6..22e3c9c 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -679,6 +679,29 @@ validate_const_int (const char *string)
     fatal_with_file_and_line ("invalid decimal constant \"%s\"\n", string);
 }
 
+static void
+validate_const_wide_int (const char *string)
+{
+  const char *cp;
+  int valid = 1;
+
+  cp = string;
+  while (*cp && ISSPACE (*cp))
+    cp++;
+  /* Skip the leading 0x.  */
+  if (cp[0] == '0' || cp[1] == 'x')
+    cp += 2;
+  else
+    valid = 0;
+  if (*cp == 0)
+    valid = 0;
+  for (; *cp; cp++)
+    if (! ISXDIGIT (*cp))
+      valid = 0;
+  if (!valid)
+    fatal_with_file_and_line ("invalid hex constant \"%s\"\n", string);
+}
+
 /* Record that PTR uses iterator ITERATOR.  */
 
 static void
@@ -1064,6 +1087,56 @@ read_rtx_code (const char *code_name)
 	gcc_unreachable ();
       }
 
+  if (CONST_WIDE_INT_P (return_rtx))
+    {
+      read_name (&name);
+      validate_const_wide_int (name.string);
+      {
+	hwivec hwiv;
+	const char *s = name.string;
+	int len;
+	int index = 0;
+	int gs = HOST_BITS_PER_WIDE_INT/4;
+	int pos;
+	char * buf = XALLOCAVEC (char, gs + 1);
+	unsigned HOST_WIDE_INT wi;
+	int wlen;
+
+	/* Skip the leading spaces.  */
+	while (*s && ISSPACE (*s))
+	  s++;
+
+	/* Skip the leading 0x.  */
+	gcc_assert (s[0] == '0');
+	gcc_assert (s[1] == 'x');
+	s += 2;
+
+	len = strlen (s);
+	pos = len - gs;
+	wlen = (len + gs - 1)/gs;	/* Number of words needed */
+
+	return_rtx = const_wide_int_alloc (wlen);
+
+	hwiv = CONST_WIDE_INT_VEC (return_rtx);
+	while (pos > 0)
+	  {
+#if HOST_BITS_PER_WIDE_INT == 64
+	    sscanf (s + pos, "%16" HOST_WIDE_INT_PRINT "x", &wi);
+#else
+	    sscanf (s + pos, "%8" HOST_WIDE_INT_PRINT "x", &wi);
+#endif
+	    XHWIVEC_ELT (hwiv, index++) = wi;
+	    pos -= gs;
+	  }
+	strncpy (buf, s, gs - pos);
+	buf [gs - pos] = 0;
+	sscanf (buf, "%" HOST_WIDE_INT_PRINT "x", &wi);
+	XHWIVEC_ELT (hwiv, index++) = wi;
+	/* TODO: After reading, do we want to canonicalize with:
+	   value = lookup_const_wide_int (value); ? */
+      }
+    }
+
   c = read_skip_spaces ();
   /* Syntactic sugar for AND and IOR, allowing Lisp-like
      arbitrary number of arguments for them.  */
diff --git a/gcc/recog.c b/gcc/recog.c
index a53f034..46fb8d0 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -1130,7 +1130,7 @@ immediate_operand (rtx op, enum machine_mode mode)
 					    : mode, op));
 }
 
-/* Returns 1 if OP is an operand that is a CONST_INT.  */
+/* Returns 1 if OP is an operand that is a CONST_INT of mode MODE.  */
 
 int
 const_int_operand (rtx op, enum machine_mode mode)
@@ -1145,8 +1145,61 @@ const_int_operand (rtx op, enum machine_mode mode)
   return 1;
 }
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns 1 if OP is an operand that is a CONST_INT or CONST_WIDE_INT
+   of mode MODE.  */
+int
+const_scalar_int_operand (rtx op, enum machine_mode mode)
+{
+  if (!CONST_SCALAR_INT_P (op))
+    return 0;
+
+  if (mode != VOIDmode)
+    {
+      int prec = GET_MODE_PRECISION (mode);
+      int bitsize = GET_MODE_BITSIZE (mode);
+      
+      if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
+	return 0;
+      
+      if (prec == bitsize)
+	return 1;
+      else
+	{
+	  /* Multiword partial int.  */
+	  HOST_WIDE_INT x 
+	    = CONST_WIDE_INT_ELT (op, CONST_WIDE_INT_NUNITS (op) - 1);
+	  return (wide_int::sext (x, prec & (HOST_BITS_PER_WIDE_INT - 1))
+		  == x);
+	}
+    }
+  return 1;
+}
+
+/* Returns 1 if OP is an operand that is a CONST_WIDE_INT of mode
+   MODE.  This most likely is not as useful as
+   const_scalar_int_operand, but is here for consistancy.  */
+int
+const_wide_int_operand (rtx op, enum machine_mode mode)
+{
+  if (!CONST_WIDE_INT_P (op))
+    return 0;
+
+  return const_scalar_int_operand (op, mode);
+}
+
+/* Returns 1 if OP is an operand that is a constant integer or constant
+   floating-point number of MODE.  */
+
+int
+const_double_operand (rtx op, enum machine_mode mode)
+{
+  return (GET_CODE (op) == CONST_DOUBLE)
+	  && (GET_MODE (op) == mode || mode == VOIDmode);
+}
+#else
 /* Returns 1 if OP is an operand that is a constant integer or constant
-   floating-point number.  */
+   floating-point number of MODE.  */
 
 int
 const_double_operand (rtx op, enum machine_mode mode)
@@ -1162,8 +1215,9 @@ const_double_operand (rtx op, enum machine_mode mode)
 	  && (mode == VOIDmode || GET_MODE (op) == mode
 	      || GET_MODE (op) == VOIDmode));
 }
-
-/* Return 1 if OP is a general operand that is not an immediate operand.  */
+#endif
+/* Return 1 if OP is a general operand that is not an immediate
+   operand of mode MODE.  */
 
 int
 nonimmediate_operand (rtx op, enum machine_mode mode)
@@ -1171,7 +1225,8 @@ nonimmediate_operand (rtx op, enum machine_mode mode)
   return (general_operand (op, mode) && ! CONSTANT_P (op));
 }
 
-/* Return 1 if OP is a register reference or immediate value of mode MODE.  */
+/* Return 1 if OP is a register reference or immediate value of mode
+   MODE.  */
 
 int
 nonmemory_operand (rtx op, enum machine_mode mode)
diff --git a/gcc/rtl.c b/gcc/rtl.c
index c42abda..b4ab1b6 100644
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -111,7 +111,7 @@ const enum rtx_class rtx_class[NUM_RTX_CODE] = {
 const unsigned char rtx_code_size[NUM_RTX_CODE] = {
 #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)				\
   (((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE			\
-    || (ENUM) == CONST_FIXED)						\
+    || (ENUM) == CONST_FIXED || (ENUM) == CONST_WIDE_INT)		\
    ? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT)	\
    : RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (rtunion)),
 
@@ -183,18 +183,24 @@ shallow_copy_rtvec (rtvec vec)
 unsigned int
 rtx_size (const_rtx x)
 {
+  if (GET_CODE (x) == CONST_WIDE_INT)
+    return (RTX_HDR_SIZE
+	    + sizeof (struct hwivec_def)
+	    + ((CONST_WIDE_INT_NUNITS (x) - 1)
+	       * sizeof (HOST_WIDE_INT)));
   if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_HAS_BLOCK_INFO_P (x))
     return RTX_HDR_SIZE + sizeof (struct block_symbol);
   return RTX_CODE_SIZE (GET_CODE (x));
 }
 
-/* Allocate an rtx of code CODE.  The CODE is stored in the rtx;
-   all the rest is initialized to zero.  */
+/* Allocate an rtx of code CODE with EXTRA bytes in it.  The CODE is
+   stored in the rtx; all the rest is initialized to zero.  */
 
 rtx
-rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
+rtx_alloc_stat_v (RTX_CODE code MEM_STAT_DECL, int extra)
 {
-  rtx rt = ggc_alloc_zone_rtx_def_stat (&rtl_zone, RTX_CODE_SIZE (code)
+  rtx rt = ggc_alloc_zone_rtx_def_stat (&rtl_zone,
+					RTX_CODE_SIZE (code) + extra
                                         PASS_MEM_STAT);
 
   /* We want to clear everything up to the FLD array.  Normally, this
@@ -213,6 +219,29 @@ rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
   return rt;
 }
 
+/* Allocate an rtx of code CODE.  The CODE is stored in the rtx;
+   all the rest is initialized to zero.  */
+
+rtx
+rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
+{
+  return rtx_alloc_stat_v (code PASS_MEM_STAT, 0);
+}
+
+/* Write the wide constant OP0 to OUTFILE.  */
+
+void
+hwivec_output_hex (FILE *outfile, const_hwivec op0)
+{
+  int i = HWI_GET_NUM_ELEM (op0);
+  gcc_assert (i > 0);
+  if (XHWIVEC_ELT (op0, i-1) == 0)
+    fprintf (outfile, "0x");
+  fprintf (outfile, HOST_WIDE_INT_PRINT_HEX, XHWIVEC_ELT (op0, --i));
+  while (--i >= 0)
+    fprintf (outfile, HOST_WIDE_INT_PRINT_PADDED_HEX, XHWIVEC_ELT (op0, i));
+}
+
 \f
 /* Return true if ORIG is a sharable CONST.  */
 
@@ -427,7 +456,6 @@ rtx_equal_p_cb (const_rtx x, const_rtx y, rtx_equal_p_callback_function cb)
 	  if (XWINT (x, i) != XWINT (y, i))
 	    return 0;
 	  break;
-
 	case 'n':
 	case 'i':
 	  if (XINT (x, i) != XINT (y, i))
@@ -645,6 +673,10 @@ iterative_hash_rtx (const_rtx x, hashval_t hash)
       return iterative_hash_object (i, hash);
     case CONST_INT:
       return iterative_hash_object (INTVAL (x), hash);
+    case CONST_WIDE_INT:
+      for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	hash = iterative_hash_object (CONST_WIDE_INT_ELT (x, i), hash);
+      return hash;
     case SYMBOL_REF:
       if (XSTR (x, 0))
 	return iterative_hash (XSTR (x, 0), strlen (XSTR (x, 0)) + 1,
@@ -810,6 +842,16 @@ rtl_check_failed_block_symbol (const char *file, int line, const char *func)
 
 /* XXX Maybe print the vector?  */
 void
+hwivec_check_failed_bounds (const_hwivec r, int n, const char *file, int line,
+			    const char *func)
+{
+  internal_error
+    ("RTL check: access of hwi elt %d of vector with last elt %d in %s, at %s:%d",
+     n, GET_NUM_ELEM (r) - 1, func, trim_filename (file), line);
+}
+
+/* XXX Maybe print the vector?  */
+void
 rtvec_check_failed_bounds (const_rtvec r, int n, const char *file, int line,
 			   const char *func)
 {
diff --git a/gcc/rtl.def b/gcc/rtl.def
index e8a6adf..1dba6de 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -319,6 +319,9 @@ DEF_RTL_EXPR(TRAP_IF, "trap_if", "ee", RTX_EXTRA)
 /* numeric integer constant */
 DEF_RTL_EXPR(CONST_INT, "const_int", "w", RTX_CONST_OBJ)
 
+/* numeric integer constant */
+DEF_RTL_EXPR(CONST_WIDE_INT, "const_wide_int", "", RTX_CONST_OBJ)
+
 /* fixed-point constant */
 DEF_RTL_EXPR(CONST_FIXED, "const_fixed", "www", RTX_CONST_OBJ)
 
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 8c45e2e..e2a8a3b 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "fixed-value.h"
 #include "alias.h"
 #include "hashtab.h"
+#include "wide-int.h"
 #include "flags.h"
 
 /* Value used by some passes to "recognize" noop moves as valid
@@ -252,6 +253,14 @@ struct GTY(()) object_block {
   VEC(rtx,gc) *anchors;
 };
 
+struct GTY((variable_size)) hwivec_def {
+  int num_elem;		/* number of elements */
+  HOST_WIDE_INT elem[1];
+};
+
+#define HWI_GET_NUM_ELEM(HWIVEC)	((HWIVEC)->num_elem)
+#define HWI_PUT_NUM_ELEM(HWIVEC, NUM)	((HWIVEC)->num_elem = (NUM))
+
 /* RTL expression ("rtx").  */
 
 struct GTY((chain_next ("RTX_NEXT (&%h)"),
@@ -344,6 +353,7 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"),
     struct block_symbol block_sym;
     struct real_value rv;
     struct fixed_value fv;
+    struct hwivec_def hwiv;
   } GTY ((special ("rtx_def"), desc ("GET_CODE (&%0)"))) u;
 };
 
@@ -382,13 +392,13 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"),
    for a variable number of things.  The principle use is inside
    PARALLEL expressions.  */
 
+#define NULL_RTVEC (rtvec) 0
+
 struct GTY((variable_size)) rtvec_def {
   int num_elem;		/* number of elements */
   rtx GTY ((length ("%h.num_elem"))) elem[1];
 };
 
-#define NULL_RTVEC (rtvec) 0
-
 #define GET_NUM_ELEM(RTVEC)		((RTVEC)->num_elem)
 #define PUT_NUM_ELEM(RTVEC, NUM)	((RTVEC)->num_elem = (NUM))
 
@@ -398,12 +408,38 @@ struct GTY((variable_size)) rtvec_def {
 /* Predicate yielding nonzero iff X is an rtx for a memory location.  */
 #define MEM_P(X) (GET_CODE (X) == MEM)
 
+#if TARGET_SUPPORTS_WIDE_INT
+
+/* Match CONST_*s that can represent compile-time constant integers.  */
+#define CASE_CONST_SCALAR_INT \
+   case CONST_INT: \
+   case CONST_WIDE_INT
+
+/* Match CONST_*s for which pointer equality corresponds to value 
+   equality.  */
+#define CASE_CONST_UNIQUE \
+   case CONST_INT: \
+   case CONST_WIDE_INT: \
+   case CONST_DOUBLE: \
+   case CONST_FIXED
+
+/* Match all CONST_* rtxes.  */
+#define CASE_CONST_ANY \
+   case CONST_INT: \
+   case CONST_WIDE_INT: \
+   case CONST_DOUBLE: \
+   case CONST_FIXED: \
+   case CONST_VECTOR
+
+#else
+
 /* Match CONST_*s that can represent compile-time constant integers.  */
 #define CASE_CONST_SCALAR_INT \
    case CONST_INT: \
    case CONST_DOUBLE
 
-/* Match CONST_*s for which pointer equality corresponds to value equality.  */
+/* Match CONST_*s for which pointer equality corresponds to value 
+equality.  */
 #define CASE_CONST_UNIQUE \
    case CONST_INT: \
    case CONST_DOUBLE: \
@@ -415,10 +451,17 @@ struct GTY((variable_size)) rtvec_def {
    case CONST_DOUBLE: \
    case CONST_FIXED: \
    case CONST_VECTOR
+#endif
+
+
+
 
 /* Predicate yielding nonzero iff X is an rtx for a constant integer.  */
 #define CONST_INT_P(X) (GET_CODE (X) == CONST_INT)
 
+/* Predicate yielding nonzero iff X is an rtx for a constant integer.  */
+#define CONST_WIDE_INT_P(X) (GET_CODE (X) == CONST_WIDE_INT)
+
 /* Predicate yielding nonzero iff X is an rtx for a constant fixed-point.  */
 #define CONST_FIXED_P(X) (GET_CODE (X) == CONST_FIXED)
 
@@ -431,8 +474,13 @@ struct GTY((variable_size)) rtvec_def {
   (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == VOIDmode)
 
 /* Predicate yielding true iff X is an rtx for a integer const.  */
+#if TARGET_SUPPORTS_WIDE_INT
+#define CONST_SCALAR_INT_P(X) \
+  (CONST_INT_P (X) || CONST_WIDE_INT_P (X))
+#else
 #define CONST_SCALAR_INT_P(X) \
   (CONST_INT_P (X) || CONST_DOUBLE_AS_INT_P (X))
+#endif
 
 /* Predicate yielding true iff X is an rtx for a double-int.  */
 #define CONST_DOUBLE_AS_FLOAT_P(X) \
@@ -595,6 +643,13 @@ struct GTY((variable_size)) rtvec_def {
 			       __FUNCTION__);				\
      &_rtx->u.hwint[_n]; }))
 
+#define XHWIVEC_ELT(HWIVEC, I) __extension__				\
+(*({ __typeof (HWIVEC) const _hwivec = (HWIVEC); const int _i = (I);	\
+     if (_i < 0 || _i >= HWI_GET_NUM_ELEM (_hwivec))			\
+       hwivec_check_failed_bounds (_hwivec, _i, __FILE__, __LINE__,	\
+				  __FUNCTION__);			\
+     &_hwivec->elem[_i]; }))
+
 #define XCWINT(RTX, N, C) __extension__					\
 (*({ __typeof (RTX) const _rtx = (RTX);					\
      if (GET_CODE (_rtx) != (C))					\
@@ -631,6 +686,11 @@ struct GTY((variable_size)) rtvec_def {
 				    __FUNCTION__);			\
    &_symbol->u.block_sym; })
 
+#define HWIVEC_CHECK(RTX,C) __extension__				\
+({ __typeof (RTX) const _symbol = (RTX);				\
+   RTL_CHECKC1 (_symbol, 0, C);						\
+   &_symbol->u.hwiv; })
+
 extern void rtl_check_failed_bounds (const_rtx, int, const char *, int,
 				     const char *)
     ATTRIBUTE_NORETURN;
@@ -651,6 +711,9 @@ extern void rtl_check_failed_code_mode (const_rtx, enum rtx_code, enum machine_m
     ATTRIBUTE_NORETURN;
 extern void rtl_check_failed_block_symbol (const char *, int, const char *)
     ATTRIBUTE_NORETURN;
+extern void hwivec_check_failed_bounds (const_rtvec, int, const char *, int,
+					const char *)
+    ATTRIBUTE_NORETURN;
 extern void rtvec_check_failed_bounds (const_rtvec, int, const char *, int,
 				       const char *)
     ATTRIBUTE_NORETURN;
@@ -663,12 +726,14 @@ extern void rtvec_check_failed_bounds (const_rtvec, int, const char *, int,
 #define RTL_CHECKC2(RTX, N, C1, C2) ((RTX)->u.fld[N])
 #define RTVEC_ELT(RTVEC, I)	    ((RTVEC)->elem[I])
 #define XWINT(RTX, N)		    ((RTX)->u.hwint[N])
+#define XHWIVEC_ELT(HWIVEC, I)	    ((HWIVEC)->elem[I])
 #define XCWINT(RTX, N, C)	    ((RTX)->u.hwint[N])
 #define XCMWINT(RTX, N, C, M)	    ((RTX)->u.hwint[N])
 #define XCNMWINT(RTX, N, C, M)	    ((RTX)->u.hwint[N])
 #define XCNMPRV(RTX, C, M)	    (&(RTX)->u.rv)
 #define XCNMPFV(RTX, C, M)	    (&(RTX)->u.fv)
 #define BLOCK_SYMBOL_CHECK(RTX)	    (&(RTX)->u.block_sym)
+#define HWIVEC_CHECK(RTX,C)	    (&(RTX)->u.hwiv)
 
 #endif
 
@@ -811,8 +876,8 @@ extern void rtl_check_failed_flag (const char *, const_rtx, const char *,
 #define XCCFI(RTX, N, C)      (RTL_CHECKC1 (RTX, N, C).rt_cfi)
 #define XCCSELIB(RTX, N, C)   (RTL_CHECKC1 (RTX, N, C).rt_cselib)
 
-#define XCVECEXP(RTX, N, M, C)	RTVEC_ELT (XCVEC (RTX, N, C), M)
-#define XCVECLEN(RTX, N, C)	GET_NUM_ELEM (XCVEC (RTX, N, C))
+#define XCVECEXP(RTX, N, M, C) RTVEC_ELT (XCVEC (RTX, N, C), M)
+#define XCVECLEN(RTX, N, C)    GET_NUM_ELEM (XCVEC (RTX, N, C))
 
 #define XC2EXP(RTX, N, C1, C2)      (RTL_CHECKC2 (RTX, N, C1, C2).rt_rtx)
 \f
@@ -1154,9 +1219,19 @@ rhs_regno (const_rtx x)
 #define INTVAL(RTX) XCWINT(RTX, 0, CONST_INT)
 #define UINTVAL(RTX) ((unsigned HOST_WIDE_INT) INTVAL (RTX))
 
+/* For a CONST_WIDE_INT, CONST_WIDE_INT_NUNITS is the number of
+   elements actually needed to represent the constant.
+   CONST_WIDE_INT_ELT gets one of the elements.  0 is the least
+   significant HOST_WIDE_INT.  */
+#define CONST_WIDE_INT_VEC(RTX) HWIVEC_CHECK (RTX, CONST_WIDE_INT)
+#define CONST_WIDE_INT_NUNITS(RTX) HWI_GET_NUM_ELEM (CONST_WIDE_INT_VEC (RTX))
+#define CONST_WIDE_INT_ELT(RTX, N) XHWIVEC_ELT (CONST_WIDE_INT_VEC (RTX), N) 
+
 /* For a CONST_DOUBLE:
+#if TARGET_SUPPORTS_WIDE_INT == 0
    For a VOIDmode, there are two integers CONST_DOUBLE_LOW is the
      low-order word and ..._HIGH the high-order.
+#endif
    For a float, there is a REAL_VALUE_TYPE structure, and
      CONST_DOUBLE_REAL_VALUE(r) is a pointer to it.  */
 #define CONST_DOUBLE_LOW(r) XCMWINT (r, 0, CONST_DOUBLE, VOIDmode)
@@ -1682,6 +1757,12 @@ extern rtx plus_constant (enum machine_mode, rtx, HOST_WIDE_INT);
 /* In rtl.c */
 extern rtx rtx_alloc_stat (RTX_CODE MEM_STAT_DECL);
 #define rtx_alloc(c) rtx_alloc_stat (c MEM_STAT_INFO)
+extern rtx rtx_alloc_stat_v (RTX_CODE MEM_STAT_DECL, int);
+#define rtx_alloc_v(c, SZ) rtx_alloc_stat_v (c MEM_STAT_INFO, SZ)
+#define const_wide_int_alloc(NWORDS)				\
+  rtx_alloc_v (CONST_WIDE_INT,					\
+	       (sizeof (struct hwivec_def)			\
+		+ ((NWORDS)-1) * sizeof (HOST_WIDE_INT)))	\
 
 extern rtvec rtvec_alloc (int);
 extern rtvec shallow_copy_rtvec (rtvec);
@@ -1738,10 +1819,17 @@ extern void start_sequence (void);
 extern void push_to_sequence (rtx);
 extern void push_to_sequence2 (rtx, rtx);
 extern void end_sequence (void);
+#if TARGET_SUPPORTS_WIDE_INT == 0
 extern double_int rtx_to_double_int (const_rtx);
-extern rtx immed_double_int_const (double_int, enum machine_mode);
+#endif
+extern void hwivec_output_hex (FILE *, const_hwivec);
+#ifndef GENERATOR_FILE
+extern rtx immed_wide_int_const (const wide_int &cst, enum machine_mode mode);
+#endif
+#if TARGET_SUPPORTS_WIDE_INT == 0
 extern rtx immed_double_const (HOST_WIDE_INT, HOST_WIDE_INT,
 			       enum machine_mode);
+#endif
 
 /* In loop-iv.c  */
 
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index fb7d45c..852a3d7 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -3081,6 +3081,8 @@ commutative_operand_precedence (rtx op)
   /* Constants always come the second operand.  Prefer "nice" constants.  */
   if (code == CONST_INT)
     return -8;
+  if (code == CONST_WIDE_INT)
+    return -8;
   if (code == CONST_DOUBLE)
     return -7;
   if (code == CONST_FIXED)
@@ -3093,6 +3095,8 @@ commutative_operand_precedence (rtx op)
     case RTX_CONST_OBJ:
       if (code == CONST_INT)
         return -6;
+      if (code == CONST_WIDE_INT)
+        return -6;
       if (code == CONST_DOUBLE)
         return -5;
       if (code == CONST_FIXED)
@@ -5274,7 +5278,10 @@ get_address_mode (rtx mem)
 /* Split up a CONST_DOUBLE or integer constant rtx
    into two rtx's for single words,
    storing in *FIRST the word that comes first in memory in the target
-   and in *SECOND the other.  */
+   and in *SECOND the other. 
+
+   TODO: This function needs to be rewritten to work on any size
+   integer.  */
 
 void
 split_double (rtx value, rtx *first, rtx *second)
@@ -5351,6 +5358,22 @@ split_double (rtx value, rtx *first, rtx *second)
 	    }
 	}
     }
+  else if (GET_CODE (value) == CONST_WIDE_INT)
+    {
+      /* All of this is scary code and needs to be converted to
+	 properly work with any size integer.  */
+      gcc_assert (CONST_WIDE_INT_NUNITS (value) == 2);
+      if (WORDS_BIG_ENDIAN)
+	{
+	  *first = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+	  *second = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+	}
+      else
+	{
+	  *first = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+	  *second = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+	}
+    }
   else if (!CONST_DOUBLE_P (value))
     {
       if (WORDS_BIG_ENDIAN)
diff --git a/gcc/sched-vis.c b/gcc/sched-vis.c
index 24403a6..5cfbae4 100644
--- a/gcc/sched-vis.c
+++ b/gcc/sched-vis.c
@@ -444,6 +444,23 @@ print_value (char *buf, const_rtx x, int verbose)
 	       (unsigned HOST_WIDE_INT) INTVAL (x));
       cur = safe_concat (buf, cur, t);
       break;
+
+    case CONST_WIDE_INT:
+      {
+	const char *sep = "<";
+	int i;
+	for (i = CONST_WIDE_INT_NUNITS (x) - 1; i >= 0; i--)
+	  {
+	    cur = safe_concat (buf, cur, sep);
+	    sep = ",";
+	    sprintf (t, HOST_WIDE_INT_PRINT_HEX,
+		     (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, i));
+	    cur = safe_concat (buf, cur, t);
+	  }
+	cur = safe_concat (buf, cur, ">");
+      }
+      break;
+
     case CONST_DOUBLE:
       if (FLOAT_MODE_P (GET_MODE (x)))
 	real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1);
diff --git a/gcc/sel-sched-ir.c b/gcc/sel-sched-ir.c
index 2a7a170..70dfd62 100644
--- a/gcc/sel-sched-ir.c
+++ b/gcc/sel-sched-ir.c
@@ -1137,10 +1137,10 @@ lhs_and_rhs_separable_p (rtx lhs, rtx rhs)
   if (lhs == NULL || rhs == NULL)
     return false;
 
-  /* Do not schedule CONST, CONST_INT and CONST_DOUBLE etc as rhs: no point
-     to use reg, if const can be used.  Moreover, scheduling const as rhs may
-     lead to mode mismatch cause consts don't have modes but they could be
-     merged from branches where the same const used in different modes.  */
+  /* Do not schedule constants as rhs: no point to use reg, if const
+     can be used.  Moreover, scheduling const as rhs may lead to mode
+     mismatch cause consts don't have modes but they could be merged
+     from branches where the same const used in different modes.  */
   if (CONSTANT_P (rhs))
     return false;
 
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 933c725..3a0d643 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -88,6 +88,22 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
   if (width <= HOST_BITS_PER_WIDE_INT
       && CONST_INT_P (x))
     val = INTVAL (x);
+#if TARGET_SUPPORTS_WIDE_INT
+  else if (CONST_WIDE_INT_P (x))
+    {
+      unsigned int i;
+      unsigned int elts = CONST_WIDE_INT_NUNITS (x);
+      if (elts != (width + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+	return false;
+      for (i = 0; i < elts - 1; i++)
+	if (CONST_WIDE_INT_ELT (x, i) != 0)
+	  return false;
+      val = CONST_WIDE_INT_ELT (x, elts - 1);
+      width %= HOST_BITS_PER_WIDE_INT;
+      if (width == 0)
+	width = HOST_BITS_PER_WIDE_INT;
+    }
+#else
   else if (width <= HOST_BITS_PER_DOUBLE_INT
 	   && CONST_DOUBLE_AS_INT_P (x)
 	   && CONST_DOUBLE_LOW (x) == 0)
@@ -95,8 +111,9 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
       val = CONST_DOUBLE_HIGH (x);
       width -= HOST_BITS_PER_WIDE_INT;
     }
+#endif
   else
-    /* FIXME: We don't yet have a representation for wider modes.  */
+    /* X is not an integer constant.  */
     return false;
 
   if (width < HOST_BITS_PER_WIDE_INT)
@@ -1271,7 +1288,6 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 				rtx op, enum machine_mode op_mode)
 {
   unsigned int width = GET_MODE_PRECISION (mode);
-  unsigned int op_width = GET_MODE_PRECISION (op_mode);
 
   if (code == VEC_DUPLICATE)
     {
@@ -1345,8 +1361,19 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       if (CONST_INT_P (op))
 	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
       else
+#if TARGET_SUPPORTS_WIDE_INT
+	{
+	  /* The conversion code to floats really want exactly 2 HWIs.
+	     This needs to be fixed.  For now, if the constant is
+	     really big, just return 0 which is safe.  */
+	  if (CONST_WIDE_INT_NUNITS (op) > 2)
+	    return 0;
+	  lv = CONST_WIDE_INT_ELT (op, 0);
+	  hv = CONST_WIDE_INT_ELT (op, 1);
+	}
+#else
 	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
-
+#endif
       REAL_VALUE_FROM_INT (d, lv, hv, mode);
       d = real_value_truncate (mode, d);
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
@@ -1359,8 +1386,19 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       if (CONST_INT_P (op))
 	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
       else
+#if TARGET_SUPPORTS_WIDE_INT
+	{
+	  /* The conversion code to floats really want exactly 2 HWIs.
+	     This needs to be fixed.  For now, if the constant is
+	     really big, just return 0 which is safe.  */
+	  if (CONST_WIDE_INT_NUNITS (op) > 2)
+	    return 0;
+	  lv = CONST_WIDE_INT_ELT (op, 0);
+	  hv = CONST_WIDE_INT_ELT (op, 1);
+	}
+#else
 	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
-
+#endif
       if (op_mode == VOIDmode
 	  || GET_MODE_PRECISION (op_mode) > HOST_BITS_PER_DOUBLE_INT)
 	/* We should never get a negative number.  */
@@ -1373,302 +1411,87 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
 
-  if (CONST_INT_P (op)
-      && width <= HOST_BITS_PER_WIDE_INT && width > 0)
+  if (CONST_SCALAR_INT_P (op) && width > 0)
     {
-      HOST_WIDE_INT arg0 = INTVAL (op);
-      HOST_WIDE_INT val;
+      wide_int result;
+      enum machine_mode imode = op_mode == VOIDmode ? mode : op_mode;
+      wide_int op0 = wide_int::from_rtx (op, imode);
+
+#if TARGET_SUPPORTS_WIDE_INT == 0
+      /* This assert keeps the simplification from producing a result
+	 that cannot be represented in a CONST_DOUBLE but a lot of
+	 upstream callers expect that this function never fails to
+	 simplify something and so you if you added this to the test
+	 above the code would die later anyway.  If this assert
+	 happens, you just need to make the port support wide int.  */
+      gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT); 
+#endif
 
       switch (code)
 	{
 	case NOT:
-	  val = ~ arg0;
+	  result = ~op0;
 	  break;
 
 	case NEG:
-	  val = - arg0;
+	  result = op0.neg ();
 	  break;
 
 	case ABS:
-	  val = (arg0 >= 0 ? arg0 : - arg0);
+	  result = op0.abs ();
 	  break;
 
 	case FFS:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = ffs_hwi (arg0);
+	  result = op0.ffs ();
 	  break;
 
 	case CLZ:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0 && CLZ_DEFINED_VALUE_AT_ZERO (mode, val))
-	    ;
-	  else
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 1;
+	  result = op0.clz (GET_MODE_BITSIZE (mode), 
+			    GET_MODE_PRECISION (mode));
 	  break;
 
 	case CLRSB:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0)
-	    val = GET_MODE_PRECISION (mode) - 1;
-	  else if (arg0 >= 0)
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 2;
-	  else if (arg0 < 0)
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (~arg0) - 2;
+	  result = op0.clrsb (GET_MODE_BITSIZE (mode), 
+			      GET_MODE_PRECISION (mode));
 	  break;
-
+	  
 	case CTZ:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0)
-	    {
-	      /* Even if the value at zero is undefined, we have to come
-		 up with some replacement.  Seems good enough.  */
-	      if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, val))
-		val = GET_MODE_PRECISION (mode);
-	    }
-	  else
-	    val = ctz_hwi (arg0);
+	  result = op0.ctz (GET_MODE_BITSIZE (mode), 
+			    GET_MODE_PRECISION (mode));
 	  break;
 
 	case POPCOUNT:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = 0;
-	  while (arg0)
-	    val++, arg0 &= arg0 - 1;
+	  result = op0.popcount (GET_MODE_BITSIZE (mode), 
+				 GET_MODE_PRECISION (mode));
 	  break;
 
 	case PARITY:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = 0;
-	  while (arg0)
-	    val++, arg0 &= arg0 - 1;
-	  val &= 1;
+	  result = op0.parity (GET_MODE_BITSIZE (mode), 
+			       GET_MODE_PRECISION (mode));
 	  break;
 
 	case BSWAP:
-	  {
-	    unsigned int s;
-
-	    val = 0;
-	    for (s = 0; s < width; s += 8)
-	      {
-		unsigned int d = width - s - 8;
-		unsigned HOST_WIDE_INT byte;
-		byte = (arg0 >> s) & 0xff;
-		val |= byte << d;
-	      }
-	  }
+	  result = op0.bswap ();
 	  break;
 
 	case TRUNCATE:
-	  val = arg0;
+	  result = op0.sext (mode);
 	  break;
 
 	case ZERO_EXTEND:
-	  /* When zero-extending a CONST_INT, we need to know its
-             original mode.  */
-	  gcc_assert (op_mode != VOIDmode);
-	  if (op_width == HOST_BITS_PER_WIDE_INT)
-	    {
-	      /* If we were really extending the mode,
-		 we would have to distinguish between zero-extension
-		 and sign-extension.  */
-	      gcc_assert (width == op_width);
-	      val = arg0;
-	    }
-	  else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
-	    val = arg0 & GET_MODE_MASK (op_mode);
-	  else
-	    return 0;
+	  result = op0.zext (mode);
 	  break;
 
 	case SIGN_EXTEND:
-	  if (op_mode == VOIDmode)
-	    op_mode = mode;
-	  op_width = GET_MODE_PRECISION (op_mode);
-	  if (op_width == HOST_BITS_PER_WIDE_INT)
-	    {
-	      /* If we were really extending the mode,
-		 we would have to distinguish between zero-extension
-		 and sign-extension.  */
-	      gcc_assert (width == op_width);
-	      val = arg0;
-	    }
-	  else if (op_width < HOST_BITS_PER_WIDE_INT)
-	    {
-	      val = arg0 & GET_MODE_MASK (op_mode);
-	      if (val_signbit_known_set_p (op_mode, val))
-		val |= ~GET_MODE_MASK (op_mode);
-	    }
-	  else
-	    return 0;
+	  result = op0.sext (mode);
 	  break;
 
 	case SQRT:
-	case FLOAT_EXTEND:
-	case FLOAT_TRUNCATE:
-	case SS_TRUNCATE:
-	case US_TRUNCATE:
-	case SS_NEG:
-	case US_NEG:
-	case SS_ABS:
-	  return 0;
-
-	default:
-	  gcc_unreachable ();
-	}
-
-      return gen_int_mode (val, mode);
-    }
-
-  /* We can do some operations on integer CONST_DOUBLEs.  Also allow
-     for a DImode operation on a CONST_INT.  */
-  else if (width <= HOST_BITS_PER_DOUBLE_INT
-	   && (CONST_DOUBLE_AS_INT_P (op) || CONST_INT_P (op)))
-    {
-      double_int first, value;
-
-      if (CONST_DOUBLE_AS_INT_P (op))
-	first = double_int::from_pair (CONST_DOUBLE_HIGH (op),
-				       CONST_DOUBLE_LOW (op));
-      else
-	first = double_int::from_shwi (INTVAL (op));
-
-      switch (code)
-	{
-	case NOT:
-	  value = ~first;
-	  break;
-
-	case NEG:
-	  value = -first;
-	  break;
-
-	case ABS:
-	  if (first.is_negative ())
-	    value = -first;
-	  else
-	    value = first;
-	  break;
-
-	case FFS:
-	  value.high = 0;
-	  if (first.low != 0)
-	    value.low = ffs_hwi (first.low);
-	  else if (first.high != 0)
-	    value.low = HOST_BITS_PER_WIDE_INT + ffs_hwi (first.high);
-	  else
-	    value.low = 0;
-	  break;
-
-	case CLZ:
-	  value.high = 0;
-	  if (first.high != 0)
-	    value.low = GET_MODE_PRECISION (mode) - floor_log2 (first.high) - 1
-	              - HOST_BITS_PER_WIDE_INT;
-	  else if (first.low != 0)
-	    value.low = GET_MODE_PRECISION (mode) - floor_log2 (first.low) - 1;
-	  else if (! CLZ_DEFINED_VALUE_AT_ZERO (mode, value.low))
-	    value.low = GET_MODE_PRECISION (mode);
-	  break;
-
-	case CTZ:
-	  value.high = 0;
-	  if (first.low != 0)
-	    value.low = ctz_hwi (first.low);
-	  else if (first.high != 0)
-	    value.low = HOST_BITS_PER_WIDE_INT + ctz_hwi (first.high);
-	  else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, value.low))
-	    value.low = GET_MODE_PRECISION (mode);
-	  break;
-
-	case POPCOUNT:
-	  value = double_int_zero;
-	  while (first.low)
-	    {
-	      value.low++;
-	      first.low &= first.low - 1;
-	    }
-	  while (first.high)
-	    {
-	      value.low++;
-	      first.high &= first.high - 1;
-	    }
-	  break;
-
-	case PARITY:
-	  value = double_int_zero;
-	  while (first.low)
-	    {
-	      value.low++;
-	      first.low &= first.low - 1;
-	    }
-	  while (first.high)
-	    {
-	      value.low++;
-	      first.high &= first.high - 1;
-	    }
-	  value.low &= 1;
-	  break;
-
-	case BSWAP:
-	  {
-	    unsigned int s;
-
-	    value = double_int_zero;
-	    for (s = 0; s < width; s += 8)
-	      {
-		unsigned int d = width - s - 8;
-		unsigned HOST_WIDE_INT byte;
-
-		if (s < HOST_BITS_PER_WIDE_INT)
-		  byte = (first.low >> s) & 0xff;
-		else
-		  byte = (first.high >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff;
-
-		if (d < HOST_BITS_PER_WIDE_INT)
-		  value.low |= byte << d;
-		else
-		  value.high |= byte << (d - HOST_BITS_PER_WIDE_INT);
-	      }
-	  }
-	  break;
-
-	case TRUNCATE:
-	  /* This is just a change-of-mode, so do nothing.  */
-	  value = first;
-	  break;
-
-	case ZERO_EXTEND:
-	  gcc_assert (op_mode != VOIDmode);
-
-	  if (op_width > HOST_BITS_PER_WIDE_INT)
-	    return 0;
-
-	  value = double_int::from_uhwi (first.low & GET_MODE_MASK (op_mode));
-	  break;
-
-	case SIGN_EXTEND:
-	  if (op_mode == VOIDmode
-	      || op_width > HOST_BITS_PER_WIDE_INT)
-	    return 0;
-	  else
-	    {
-	      value.low = first.low & GET_MODE_MASK (op_mode);
-	      if (val_signbit_known_set_p (op_mode, value.low))
-		value.low |= ~GET_MODE_MASK (op_mode);
-
-	      value.high = HWI_SIGN_EXTEND (value.low);
-	    }
-	  break;
-
-	case SQRT:
-	  return 0;
-
 	default:
 	  return 0;
 	}
 
-      return immed_double_int_const (value, mode);
+      return immed_wide_int_const (result, mode);
     }
 
   else if (CONST_DOUBLE_AS_FLOAT_P (op) 
@@ -1720,7 +1543,6 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	}
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
-
   else if (CONST_DOUBLE_AS_FLOAT_P (op)
 	   && SCALAR_FLOAT_MODE_P (GET_MODE (op))
 	   && GET_MODE_CLASS (mode) == MODE_INT
@@ -1733,9 +1555,14 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 
       /* This was formerly used only for non-IEEE float.
 	 eggert@twinsun.com says it is safe for IEEE also.  */
-      HOST_WIDE_INT xh, xl, th, tl;
+      HOST_WIDE_INT th, tl;
       REAL_VALUE_TYPE x, t;
+      wide_int wc;
       REAL_VALUE_FROM_CONST_DOUBLE (x, op);
+      wc.set_precision (GET_MODE_PRECISION (mode));
+      wc.set_bitsize (GET_MODE_BITSIZE (mode));
+      wc.set_len (2);
+
       switch (code)
 	{
 	case FIX:
@@ -1757,8 +1584,8 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  real_from_integer (&t, VOIDmode, tl, th, 0);
 	  if (REAL_VALUES_LESS (t, x))
 	    {
-	      xh = th;
-	      xl = tl;
+	      wc.elt_ref (1) = th;
+	      wc.elt_ref (0) = tl;
 	      break;
 	    }
 
@@ -1777,11 +1604,11 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  real_from_integer (&t, VOIDmode, tl, th, 0);
 	  if (REAL_VALUES_LESS (x, t))
 	    {
-	      xh = th;
-	      xl = tl;
+	      wc.elt_ref (1) = th;
+	      wc.elt_ref (0) = tl;
 	      break;
 	    }
-	  REAL_VALUE_TO_INT (&xl, &xh, x);
+	  REAL_VALUE_TO_INT (&wc.elt_ref (0), &wc.elt_ref (1), x);
 	  break;
 
 	case UNSIGNED_FIX:
@@ -1808,18 +1635,19 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  real_from_integer (&t, VOIDmode, tl, th, 1);
 	  if (REAL_VALUES_LESS (t, x))
 	    {
-	      xh = th;
-	      xl = tl;
+	      wc.elt_ref (1) = th;
+	      wc.elt_ref (0) = tl;
 	      break;
 	    }
 
-	  REAL_VALUE_TO_INT (&xl, &xh, x);
+	  REAL_VALUE_TO_INT (&wc.elt_ref (0), &wc.elt_ref (1), x);
 	  break;
 
 	default:
 	  gcc_unreachable ();
 	}
-      return immed_double_const (xl, xh, mode);
+      wc.canonize ();
+      return immed_wide_int_const (wc, mode);
     }
 
   return NULL_RTX;
@@ -1979,49 +1807,50 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       if (SCALAR_INT_MODE_P (mode))
 	{
-	  double_int coeff0, coeff1;
+	  wide_int coeff0;
+	  wide_int coeff1;
 	  rtx lhs = op0, rhs = op1;
 
-	  coeff0 = double_int_one;
-	  coeff1 = double_int_one;
+	  coeff0 = wide_int::one (mode);
+	  coeff1 = wide_int::one (mode);
 
 	  if (GET_CODE (lhs) == NEG)
 	    {
-	      coeff0 = double_int_minus_one;
+	      coeff0 = wide_int::minus_one (mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == MULT
 		   && CONST_INT_P (XEXP (lhs, 1)))
 	    {
-	      coeff0 = double_int::from_shwi (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::from_rtx (XEXP (lhs, 1), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == ASHIFT
 		   && CONST_INT_P (XEXP (lhs, 1))
                    && INTVAL (XEXP (lhs, 1)) >= 0
-		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (lhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff0 = double_int_zero.set_bit (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::set_bit_in_zero (INTVAL (XEXP (lhs, 1)), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 
 	  if (GET_CODE (rhs) == NEG)
 	    {
-	      coeff1 = double_int_minus_one;
+	      coeff1 = wide_int::minus_one (mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == MULT
 		   && CONST_INT_P (XEXP (rhs, 1)))
 	    {
-	      coeff1 = double_int::from_shwi (INTVAL (XEXP (rhs, 1)));
+	      coeff1 = wide_int::from_rtx (XEXP (rhs, 1), mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == ASHIFT
 		   && CONST_INT_P (XEXP (rhs, 1))
 		   && INTVAL (XEXP (rhs, 1)) >= 0
-		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (rhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff1 = double_int_zero.set_bit (INTVAL (XEXP (rhs, 1)));
+	      coeff1 = wide_int::set_bit_in_zero (INTVAL (XEXP (rhs, 1)), mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 
@@ -2029,11 +1858,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	    {
 	      rtx orig = gen_rtx_PLUS (mode, op0, op1);
 	      rtx coeff;
-	      double_int val;
 	      bool speed = optimize_function_for_speed_p (cfun);
 
-	      val = coeff0 + coeff1;
-	      coeff = immed_double_int_const (val, mode);
+	      coeff = immed_wide_int_const (coeff0 + coeff1, mode);
 
 	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
 	      return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
@@ -2155,50 +1982,52 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       if (SCALAR_INT_MODE_P (mode))
 	{
-	  double_int coeff0, negcoeff1;
+	  wide_int coeff0;
+	  wide_int negcoeff1;
 	  rtx lhs = op0, rhs = op1;
 
-	  coeff0 = double_int_one;
-	  negcoeff1 = double_int_minus_one;
+	  coeff0 = wide_int::one (mode);
+	  negcoeff1 = wide_int::minus_one (mode);
 
 	  if (GET_CODE (lhs) == NEG)
 	    {
-	      coeff0 = double_int_minus_one;
+	      coeff0 = wide_int::minus_one (mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == MULT
-		   && CONST_INT_P (XEXP (lhs, 1)))
+		   && CONST_SCALAR_INT_P (XEXP (lhs, 1)))
 	    {
-	      coeff0 = double_int::from_shwi (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::from_rtx (XEXP (lhs, 1), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == ASHIFT
 		   && CONST_INT_P (XEXP (lhs, 1))
 		   && INTVAL (XEXP (lhs, 1)) >= 0
-		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (lhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff0 = double_int_zero.set_bit (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::set_bit_in_zero (INTVAL (XEXP (lhs, 1)), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 
 	  if (GET_CODE (rhs) == NEG)
 	    {
-	      negcoeff1 = double_int_one;
+	      negcoeff1 = wide_int::one (mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == MULT
 		   && CONST_INT_P (XEXP (rhs, 1)))
 	    {
-	      negcoeff1 = double_int::from_shwi (-INTVAL (XEXP (rhs, 1)));
+	      negcoeff1 = wide_int::from_rtx (XEXP (rhs, 1), mode).neg ();
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == ASHIFT
 		   && CONST_INT_P (XEXP (rhs, 1))
 		   && INTVAL (XEXP (rhs, 1)) >= 0
-		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (rhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      negcoeff1 = double_int_zero.set_bit (INTVAL (XEXP (rhs, 1)));
-	      negcoeff1 = -negcoeff1;
+	      negcoeff1 = wide_int::set_bit_in_zero (INTVAL (XEXP (rhs, 1)),
+						    mode);
+	      negcoeff1 = negcoeff1.neg ();
 	      rhs = XEXP (rhs, 0);
 	    }
 
@@ -2206,11 +2035,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	    {
 	      rtx orig = gen_rtx_MINUS (mode, op0, op1);
 	      rtx coeff;
-	      double_int val;
 	      bool speed = optimize_function_for_speed_p (cfun);
 
-	      val = coeff0 + negcoeff1;
-	      coeff = immed_double_int_const (val, mode);
+	      coeff = immed_wide_int_const (coeff0 + negcoeff1, mode);
 
 	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
 	      return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
@@ -2362,8 +2189,21 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	  && trueop1 == CONST1_RTX (mode))
 	return op0;
 
-      /* Convert multiply by constant power of two into shift unless
-	 we are still generating RTL.  This test is a kludge.  */
+      /* Convert multiply by constant power of two into shift.  */
+#if TARGET_SUPPORTS_WIDE_INT
+      if (CONST_SCALAR_INT_P (trueop1))
+	{
+	  val = wide_int::from_rtx (trueop1, mode).exact_log2 ();
+	  if (val > 0)
+	    {
+	      unsigned int bitsize = GET_MODE_BITSIZE (mode);
+	      if (SHIFT_COUNT_TRUNCATED && val >= bitsize)
+		val %= bitsize;
+	      if (val < bitsize)
+		return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
+	    }
+	}
+#else
       if (CONST_INT_P (trueop1)
 	  && (val = exact_log2 (UINTVAL (trueop1))) >= 0
 	  /* If the mode is larger than the host word size, and the
@@ -2382,7 +2222,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	      || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT))
 	return simplify_gen_binary (ASHIFT, mode, op0,
 				    GEN_INT (val + HOST_BITS_PER_WIDE_INT));
-
+#endif
       /* x*2 is x+x and x*(-1) is -x */
       if (CONST_DOUBLE_AS_FLOAT_P (trueop1)
 	  && SCALAR_FLOAT_MODE_P (GET_MODE (trueop1))
@@ -3420,9 +3260,9 @@ rtx
 simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 				 rtx op0, rtx op1)
 {
-  HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
-  HOST_WIDE_INT val;
+#if TARGET_SUPPORTS_WIDE_INT == 0
   unsigned int width = GET_MODE_PRECISION (mode);
+#endif
 
   if (VECTOR_MODE_P (mode)
       && code != VEC_CONCAT
@@ -3615,299 +3455,128 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
   /* We can fold some multi-word operations.  */
   if (GET_MODE_CLASS (mode) == MODE_INT
-      && width == HOST_BITS_PER_DOUBLE_INT
-      && (CONST_DOUBLE_AS_INT_P (op0) || CONST_INT_P (op0))
-      && (CONST_DOUBLE_AS_INT_P (op1) || CONST_INT_P (op1)))
+      && CONST_SCALAR_INT_P (op0)
+      && CONST_SCALAR_INT_P (op1))
     {
-      double_int o0, o1, res, tmp;
-      bool overflow;
-
-      o0 = rtx_to_double_int (op0);
-      o1 = rtx_to_double_int (op1);
-
+      wide_int result;
+      wide_int wop0 = wide_int::from_rtx (op0, mode);
+      wide_int wop1 = wide_int::from_rtx (op1, mode);
+      bool overflow = false;
+
+#if TARGET_SUPPORTS_WIDE_INT == 0
+      /* This assert keeps the simplification from producing a result
+	 that cannot be represented in a CONST_DOUBLE but a lot of
+	 upstream callers expect that this function never fails to
+	 simplify something and so you if you added this to the test
+	 above the code would die later anyway.  If this assert
+	 happens, you just need to make the port support wide int.  */
+      gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT);
+#endif
       switch (code)
 	{
 	case MINUS:
-	  /* A - B == A + (-B).  */
-	  o1 = -o1;
-
-	  /* Fall through....  */
+	  result = wop0 - wop1;
+	  break;
 
 	case PLUS:
-	  res = o0 + o1;
+	  result = wop0 + wop1;
 	  break;
 
 	case MULT:
-	  res = o0 * o1;
+	  result = wop0 * wop1;
 	  break;
 
 	case DIV:
-          res = o0.divmod_with_overflow (o1, false, TRUNC_DIV_EXPR,
-					 &tmp, &overflow);
+	  result = wop0.div_trunc (wop1, wide_int::SIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
-
+	  
 	case MOD:
-          tmp = o0.divmod_with_overflow (o1, false, TRUNC_DIV_EXPR,
-					 &res, &overflow);
+	  result = wop0.mod_trunc (wop1, wide_int::SIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case UDIV:
-          res = o0.divmod_with_overflow (o1, true, TRUNC_DIV_EXPR,
-					 &tmp, &overflow);
+	  result = wop0.div_trunc (wop1, wide_int::UNSIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case UMOD:
-          tmp = o0.divmod_with_overflow (o1, true, TRUNC_DIV_EXPR,
-					 &res, &overflow);
+	  result = wop0.mod_trunc (wop1, wide_int::UNSIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case AND:
-	  res = o0 & o1;
+	  result = wop0 & wop1;
 	  break;
 
 	case IOR:
-	  res = o0 | o1;
+	  result = wop0 | wop1;
 	  break;
 
 	case XOR:
-	  res = o0 ^ o1;
+	  result = wop0 ^ wop1;
 	  break;
 
 	case SMIN:
-	  res = o0.smin (o1);
+	  result = wop0.smin (wop1);
 	  break;
 
 	case SMAX:
-	  res = o0.smax (o1);
+	  result = wop0.smax (wop1);
 	  break;
 
 	case UMIN:
-	  res = o0.umin (o1);
+	  result = wop0.umin (wop1);
 	  break;
 
 	case UMAX:
-	  res = o0.umax (o1);
-	  break;
-
-	case LSHIFTRT:   case ASHIFTRT:
-	case ASHIFT:
-	case ROTATE:     case ROTATERT:
-	  {
-	    unsigned HOST_WIDE_INT cnt;
-
-	    if (SHIFT_COUNT_TRUNCATED)
-	      {
-		o1.high = 0; 
-		o1.low &= GET_MODE_PRECISION (mode) - 1;
-	      }
-
-	    if (!o1.fits_uhwi ()
-	        || o1.to_uhwi () >= GET_MODE_PRECISION (mode))
-	      return 0;
-
-	    cnt = o1.to_uhwi ();
-	    unsigned short prec = GET_MODE_PRECISION (mode);
-
-	    if (code == LSHIFTRT || code == ASHIFTRT)
-	      res = o0.rshift (cnt, prec, code == ASHIFTRT);
-	    else if (code == ASHIFT)
-	      res = o0.alshift (cnt, prec);
-	    else if (code == ROTATE)
-	      res = o0.lrotate (cnt, prec);
-	    else /* code == ROTATERT */
-	      res = o0.rrotate (cnt, prec);
-	  }
-	  break;
-
-	default:
-	  return 0;
-	}
-
-      return immed_double_int_const (res, mode);
-    }
-
-  if (CONST_INT_P (op0) && CONST_INT_P (op1)
-      && width <= HOST_BITS_PER_WIDE_INT && width != 0)
-    {
-      /* Get the integer argument values in two forms:
-         zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S.  */
-
-      arg0 = INTVAL (op0);
-      arg1 = INTVAL (op1);
-
-      if (width < HOST_BITS_PER_WIDE_INT)
-        {
-          arg0 &= GET_MODE_MASK (mode);
-          arg1 &= GET_MODE_MASK (mode);
-
-          arg0s = arg0;
-	  if (val_signbit_known_set_p (mode, arg0s))
-	    arg0s |= ~GET_MODE_MASK (mode);
-
-          arg1s = arg1;
-	  if (val_signbit_known_set_p (mode, arg1s))
-	    arg1s |= ~GET_MODE_MASK (mode);
-	}
-      else
-	{
-	  arg0s = arg0;
-	  arg1s = arg1;
-	}
-
-      /* Compute the value of the arithmetic.  */
-
-      switch (code)
-	{
-	case PLUS:
-	  val = arg0s + arg1s;
-	  break;
-
-	case MINUS:
-	  val = arg0s - arg1s;
+	  result = wop0.umax (wop1);
 	  break;
 
-	case MULT:
-	  val = arg0s * arg1s;
-	  break;
-
-	case DIV:
-	  if (arg1s == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = arg0s / arg1s;
-	  break;
-
-	case MOD:
-	  if (arg1s == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = arg0s % arg1s;
-	  break;
-
-	case UDIV:
-	  if (arg1 == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = (unsigned HOST_WIDE_INT) arg0 / arg1;
-	  break;
-
-	case UMOD:
-	  if (arg1 == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = (unsigned HOST_WIDE_INT) arg0 % arg1;
-	  break;
-
-	case AND:
-	  val = arg0 & arg1;
-	  break;
-
-	case IOR:
-	  val = arg0 | arg1;
-	  break;
+	case LSHIFTRT:
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	case XOR:
-	  val = arg0 ^ arg1;
+	  result = wop0.rshiftu (wop1, wide_int::TRUNC);
 	  break;
-
-	case LSHIFTRT:
-	case ASHIFT:
+	  
 	case ASHIFTRT:
-	  /* Truncate the shift if SHIFT_COUNT_TRUNCATED, otherwise make sure
-	     the value is in range.  We can't return any old value for
-	     out-of-range arguments because either the middle-end (via
-	     shift_truncation_mask) or the back-end might be relying on
-	     target-specific knowledge.  Nor can we rely on
-	     shift_truncation_mask, since the shift might not be part of an
-	     ashlM3, lshrM3 or ashrM3 instruction.  */
-	  if (SHIFT_COUNT_TRUNCATED)
-	    arg1 = (unsigned HOST_WIDE_INT) arg1 % width;
-	  else if (arg1 < 0 || arg1 >= GET_MODE_BITSIZE (mode))
-	    return 0;
-
-	  val = (code == ASHIFT
-		 ? ((unsigned HOST_WIDE_INT) arg0) << arg1
-		 : ((unsigned HOST_WIDE_INT) arg0) >> arg1);
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	  /* Sign-extend the result for arithmetic right shifts.  */
-	  if (code == ASHIFTRT && arg0s < 0 && arg1 > 0)
-	    val |= ((unsigned HOST_WIDE_INT) (-1)) << (width - arg1);
+	  result = wop0.rshifts (wop1, wide_int::TRUNC);
 	  break;
+	  
+	case ASHIFT:
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	case ROTATERT:
-	  if (arg1 < 0)
-	    return 0;
-
-	  arg1 %= width;
-	  val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
-		 | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
+	  result = wop0.lshift (wop1, wide_int::TRUNC);
 	  break;
-
+	  
 	case ROTATE:
-	  if (arg1 < 0)
-	    return 0;
-
-	  arg1 %= width;
-	  val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
-		 | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
-	  break;
-
-	case COMPARE:
-	  /* Do nothing here.  */
-	  return 0;
-
-	case SMIN:
-	  val = arg0s <= arg1s ? arg0s : arg1s;
-	  break;
-
-	case UMIN:
-	  val = ((unsigned HOST_WIDE_INT) arg0
-		 <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
-	  break;
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	case SMAX:
-	  val = arg0s > arg1s ? arg0s : arg1s;
+	  result = wop0.lrotate (wop1);
 	  break;
+	  
+	case ROTATERT:
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	case UMAX:
-	  val = ((unsigned HOST_WIDE_INT) arg0
-		 > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
+	  result = wop0.rrotate (wop1);
 	  break;
 
-	case SS_PLUS:
-	case US_PLUS:
-	case SS_MINUS:
-	case US_MINUS:
-	case SS_MULT:
-	case US_MULT:
-	case SS_DIV:
-	case US_DIV:
-	case SS_ASHIFT:
-	case US_ASHIFT:
-	  /* ??? There are simplifications that can be done.  */
-	  return 0;
-
 	default:
-	  gcc_unreachable ();
+	  return NULL_RTX;
 	}
-
-      return gen_int_mode (val, mode);
+      return immed_wide_int_const (result, mode);
     }
 
   return NULL_RTX;
@@ -4573,10 +4242,11 @@ comparison_result (enum rtx_code code, int known_results)
     }
 }
 
-/* Check if the given comparison (done in the given MODE) is actually a
-   tautology or a contradiction.
-   If no simplification is possible, this function returns zero.
-   Otherwise, it returns either const_true_rtx or const0_rtx.  */
+/* Check if the given comparison (done in the given MODE) is actually
+   a tautology or a contradiction.  If the mode is VOID_mode, the
+   comparison is done in "infinite precision".  If no simplification
+   is possible, this function returns zero.  Otherwise, it returns
+   either const_true_rtx or const0_rtx.  */
 
 rtx
 simplify_const_relational_operation (enum rtx_code code,
@@ -4700,59 +4370,25 @@ simplify_const_relational_operation (enum rtx_code code,
 
   /* Otherwise, see if the operands are both integers.  */
   if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
-       && (CONST_DOUBLE_AS_INT_P (trueop0) || CONST_INT_P (trueop0))
-       && (CONST_DOUBLE_AS_INT_P (trueop1) || CONST_INT_P (trueop1)))
+      && CONST_SCALAR_INT_P (trueop0) && CONST_SCALAR_INT_P (trueop1))
     {
-      int width = GET_MODE_PRECISION (mode);
-      HOST_WIDE_INT l0s, h0s, l1s, h1s;
-      unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
-
-      /* Get the two words comprising each integer constant.  */
-      if (CONST_DOUBLE_AS_INT_P (trueop0))
-	{
-	  l0u = l0s = CONST_DOUBLE_LOW (trueop0);
-	  h0u = h0s = CONST_DOUBLE_HIGH (trueop0);
-	}
-      else
-	{
-	  l0u = l0s = INTVAL (trueop0);
-	  h0u = h0s = HWI_SIGN_EXTEND (l0s);
-	}
-
-      if (CONST_DOUBLE_AS_INT_P (trueop1))
-	{
-	  l1u = l1s = CONST_DOUBLE_LOW (trueop1);
-	  h1u = h1s = CONST_DOUBLE_HIGH (trueop1);
-	}
-      else
-	{
-	  l1u = l1s = INTVAL (trueop1);
-	  h1u = h1s = HWI_SIGN_EXTEND (l1s);
-	}
-
-      /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
-	 we have to sign or zero-extend the values.  */
-      if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
-	{
-	  l0u &= GET_MODE_MASK (mode);
-	  l1u &= GET_MODE_MASK (mode);
-
-	  if (val_signbit_known_set_p (mode, l0s))
-	    l0s |= ~GET_MODE_MASK (mode);
-
-	  if (val_signbit_known_set_p (mode, l1s))
-	    l1s |= ~GET_MODE_MASK (mode);
-	}
-      if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
-	h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
-
-      if (h0u == h1u && l0u == l1u)
+      enum machine_mode cmode = mode;
+      wide_int wo0;
+      wide_int wo1;
+
+      /* It would be nice if we really had a mode here.  However, the
+	 largest int representable on the target is as good as
+	 infinite.  */
+      if (mode == VOIDmode)
+	cmode = MAX_MODE_INT;
+      wo0 = wide_int::from_rtx (trueop0, cmode);
+      wo1 = wide_int::from_rtx (trueop1, cmode);
+      if (wo0 == wo1)
 	return comparison_result (code, CMP_EQ);
       else
 	{
-	  int cr;
-	  cr = (h0s < h1s || (h0s == h1s && l0u < l1u)) ? CMP_LT : CMP_GT;
-	  cr |= (h0u < h1u || (h0u == h1u && l0u < l1u)) ? CMP_LTU : CMP_GTU;
+	  int cr = wo0.lts_p (wo1) ? CMP_LT : CMP_GT;
+	  cr |= wo0.ltu_p (wo1) ? CMP_LTU : CMP_GTU;
 	  return comparison_result (code, cr);
 	}
     }
@@ -5167,9 +4803,9 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
   return 0;
 }
 
-/* Evaluate a SUBREG of a CONST_INT or CONST_DOUBLE or CONST_FIXED
-   or CONST_VECTOR,
-   returning another CONST_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
+/* Evaluate a SUBREG of a CONST_INT or CONST_WIDE_INT or CONST_DOUBLE
+   or CONST_FIXED or CONST_VECTOR, returning another CONST_INT or
+   CONST_WIDE_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
 
    Works by unpacking OP into a collection of 8-bit values
    represented as a little-endian array of 'unsigned char', selecting by BYTE,
@@ -5179,13 +4815,11 @@ static rtx
 simplify_immed_subreg (enum machine_mode outermode, rtx op,
 		       enum machine_mode innermode, unsigned int byte)
 {
-  /* We support up to 512-bit values (for V8DFmode).  */
   enum {
-    max_bitsize = 512,
     value_bit = 8,
     value_mask = (1 << value_bit) - 1
   };
-  unsigned char value[max_bitsize / value_bit];
+  unsigned char value [MAX_BITSIZE_MODE_ANY_MODE/value_bit];
   int value_start;
   int i;
   int elem;
@@ -5197,6 +4831,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
   rtvec result_v = NULL;
   enum mode_class outer_class;
   enum machine_mode outer_submode;
+  int max_bitsize;
 
   /* Some ports misuse CCmode.  */
   if (GET_MODE_CLASS (outermode) == MODE_CC && CONST_INT_P (op))
@@ -5206,6 +4841,9 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
   if (COMPLEX_MODE_P (outermode))
     return NULL_RTX;
 
+  /* We support any size mode.  */
+  max_bitsize = MAX (GET_MODE_BITSIZE (outermode), GET_MODE_BITSIZE (innermode));
+
   /* Unpack the value.  */
 
   if (GET_CODE (op) == CONST_VECTOR)
@@ -5255,8 +4893,20 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	    *vp++ = INTVAL (el) < 0 ? -1 : 0;
 	  break;
 
+	case CONST_WIDE_INT:
+	  {
+	    wide_int val = wide_int::from_rtx (el, innermode);
+	    unsigned char extend = val.sign_mask ();
+
+	    for (i = 0; i < elem_bitsize; i += value_bit) 
+	      *vp++ = val.extract_to_hwi (i, value_bit);
+	    for (; i < elem_bitsize; i += value_bit)
+	      *vp++ = extend;
+	  }
+	  break;
+
 	case CONST_DOUBLE:
-	  if (GET_MODE (el) == VOIDmode)
+	  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (el) == VOIDmode)
 	    {
 	      unsigned char extend = 0;
 	      /* If this triggers, someone should have generated a
@@ -5279,7 +4929,8 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	    }
 	  else
 	    {
-	      long tmp[max_bitsize / 32];
+	      /* This is big enough for anything on the platform.  */
+	      long tmp[MAX_BITSIZE_MODE_ANY_MODE / 32];
 	      int bitsize = GET_MODE_BITSIZE (GET_MODE (el));
 
 	      gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (el)));
@@ -5399,24 +5050,28 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	case MODE_INT:
 	case MODE_PARTIAL_INT:
 	  {
-	    unsigned HOST_WIDE_INT hi = 0, lo = 0;
-
-	    for (i = 0;
-		 i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
-		 i += value_bit)
-	      lo |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
-	    for (; i < elem_bitsize; i += value_bit)
-	      hi |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask)
-		     << (i - HOST_BITS_PER_WIDE_INT);
-
-	    /* immed_double_const doesn't call trunc_int_for_mode.  I don't
-	       know why.  */
-	    if (elem_bitsize <= HOST_BITS_PER_WIDE_INT)
-	      elems[elem] = gen_int_mode (lo, outer_submode);
-	    else if (elem_bitsize <= HOST_BITS_PER_DOUBLE_INT)
-	      elems[elem] = immed_double_const (lo, hi, outer_submode);
-	    else
-	      return NULL_RTX;
+	    int u;
+	    int base = 0;
+	    int units 
+	      = (GET_MODE_BITSIZE (outer_submode) + HOST_BITS_PER_WIDE_INT - 1) 
+	      / HOST_BITS_PER_WIDE_INT;
+	    wide_int r;
+	    for (u = 0; u < units; u++) 
+	      {
+		unsigned HOST_WIDE_INT buf = 0;
+		for (i = 0; 
+		     i < HOST_BITS_PER_WIDE_INT && base + i < elem_bitsize; 
+		     i += value_bit)
+		  buf |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
+
+		r.elt_ref (u) = buf;
+		base += HOST_BITS_PER_WIDE_INT;
+	      }
+	    r.set_len (units);
+	    r.set_precision (GET_MODE_PRECISION (outer_submode));
+	    r.set_bitsize (GET_MODE_BITSIZE (outer_submode));
+	    r.canonize ();
+	    elems[elem] = immed_wide_int_const (r, outer_submode);
 	  }
 	  break;
 
@@ -5424,7 +5079,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	case MODE_DECIMAL_FLOAT:
 	  {
 	    REAL_VALUE_TYPE r;
-	    long tmp[max_bitsize / 32];
+	    long tmp[MAX_BITSIZE_MODE_ANY_INT / 32];
 
 	    /* real_from_target wants its input in words affected by
 	       FLOAT_WORDS_BIG_ENDIAN.  However, we ignore this,
diff --git a/gcc/tree-ssa-address.c b/gcc/tree-ssa-address.c
index c5b8ff1..ce69e51 100644
--- a/gcc/tree-ssa-address.c
+++ b/gcc/tree-ssa-address.c
@@ -192,15 +192,18 @@ addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
   struct mem_addr_template *templ;
 
   if (addr->step && !integer_onep (addr->step))
-    st = immed_double_int_const (tree_to_double_int (addr->step), pointer_mode);
+    st = immed_wide_int_const (wide_int::from_tree (addr->step),
+			       TYPE_MODE (TREE_TYPE (addr->step)));
   else
     st = NULL_RTX;
 
   if (addr->offset && !integer_zerop (addr->offset))
-    off = immed_double_int_const
-	    (tree_to_double_int (addr->offset)
-	     .sext (TYPE_PRECISION (TREE_TYPE (addr->offset))),
-	     pointer_mode);
+    {
+      wide_int dc = wide_int::from_tree (addr->offset);
+      dc = dc.sext (TYPE_PRECISION (TREE_TYPE (addr->offset)));
+      off = immed_wide_int_const (dc,
+			       TYPE_MODE (TREE_TYPE (addr->offset)));
+    }
   else
     off = NULL_RTX;
 
diff --git a/gcc/tree.c b/gcc/tree.c
index 7f620e5..2af5fca 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -61,6 +61,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "except.h"
 #include "debug.h"
 #include "intl.h"
+#include "wide-int.h"
 
 /* Tree code classes.  */
 
@@ -1067,6 +1068,23 @@ double_int_to_tree (tree type, double_int cst)
   return build_int_cst_wide (type, cst.low, cst.high);
 }
 
+/* Constructs tree in type TYPE from with value given by CST.  Signedness
+   of CST is assumed to be the same as the signedness of TYPE.  */
+
+tree
+wide_int_to_tree (tree type, const wide_int &cst)
+{
+  wide_int v;
+
+  gcc_assert (cst.get_len () <= 2);
+  if (TYPE_UNSIGNED (type))
+    v = cst.zext (TYPE_PRECISION (type));
+  else
+    v = cst.sext (TYPE_PRECISION (type));
+
+  return build_int_cst_wide (type, v.elt (0), v.elt (1));
+}
+
 /* Returns true if CST fits into range of TYPE.  Signedness of CST is assumed
    to be the same as the signedness of TYPE.  */
 
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index bbd2f4b..fb6bc1c 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -3386,6 +3386,23 @@ loc_cmp (rtx x, rtx y)
       default:
 	gcc_unreachable ();
       }
+  if (CONST_WIDE_INT_P (x))
+    {
+      /* Compare the vector length first.  */
+      if (CONST_WIDE_INT_NUNITS (x) >= CONST_WIDE_INT_NUNITS (y))
+	return 1;
+      else if (CONST_WIDE_INT_NUNITS (x) < CONST_WIDE_INT_NUNITS (y))
+	return -1;
+
+      /* Compare the vectors elements.  */;
+      for (j = CONST_WIDE_INT_NUNITS (x) - 1; j >= 0 ; j--)
+	{
+	  if (CONST_WIDE_INT_ELT (x, j) < CONST_WIDE_INT_ELT (y, j))
+	    return -1;
+	  if (CONST_WIDE_INT_ELT (x, j) > CONST_WIDE_INT_ELT (y, j))
+	    return 1;
+	}
+    }
 
   return 0;
 }
diff --git a/gcc/varasm.c b/gcc/varasm.c
index a587c80..2eaaf03 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -3358,6 +3358,7 @@ const_rtx_hash_1 (rtx *xp, void *data)
   enum rtx_code code;
   hashval_t h, *hp;
   rtx x;
+  int i;
 
   x = *xp;
   code = GET_CODE (x);
@@ -3368,12 +3369,12 @@ const_rtx_hash_1 (rtx *xp, void *data)
     {
     case CONST_INT:
       hwi = INTVAL (x);
+
     fold_hwi:
       {
 	int shift = sizeof (hashval_t) * CHAR_BIT;
 	const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t);
-	int i;
-
+	
 	h ^= (hashval_t) hwi;
 	for (i = 1; i < n; ++i)
 	  {
@@ -3383,8 +3384,17 @@ const_rtx_hash_1 (rtx *xp, void *data)
       }
       break;
 
+    case CONST_WIDE_INT:
+      hwi = GET_MODE_PRECISION (mode);
+      {
+	int i;
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hwi ^= CONST_WIDE_INT_ELT (x, i);
+	goto fold_hwi;
+      }
+
     case CONST_DOUBLE:
-      if (mode == VOIDmode)
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && mode == VOIDmode)
 	{
 	  hwi = CONST_DOUBLE_LOW (x) ^ CONST_DOUBLE_HIGH (x);
 	  goto fold_hwi;

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - patch 5 - the rest of the rtl stuff.
  2012-10-09 18:51                                         ` patch to fix constant math - patch 5 - the rest of the rtl stuff Kenneth Zadeck
@ 2012-10-19 16:52                                           ` Richard Sandiford
  0 siblings, 0 replies; 217+ messages in thread
From: Richard Sandiford @ 2012-10-19 16:52 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Richard Guenther, Mike Stump, gcc-patches

I can't approve this, but some comments:

Kenneth Zadeck <zadeck@naturalbridge.com> writes:
> diff --git a/gcc/alias.c b/gcc/alias.c
> index 0c6a744..9e67823 100644
> --- a/gcc/alias.c
> +++ b/gcc/alias.c
> @@ -1490,9 +1490,9 @@ rtx_equal_for_memref_p (const_rtx x, const_rtx y)
>  
>      case VALUE:
>      CASE_CONST_UNIQUE:
> -      /* There's no need to compare the contents of CONST_DOUBLEs or
> -	 CONST_INTs because pointer equality is a good enough
> -	 comparison for these nodes.  */
> +      /* There's no need to compare the contents of CONST_DOUBLEs,
> +	 CONST_INTs or CONST_WIDE_INTs because pointer equality is a
> +	 good enough comparison for these nodes.  */
>        return 0;
>  
>      default:

Maybe just:

      /* Pointer equality guarantees value equality for these codes.  */

> @@ -695,13 +700,14 @@ c_readstr (const char *str, enum machine_mode mode)
>  	  && GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
>  	j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
>        j *= BITS_PER_UNIT;
> -      gcc_assert (j < HOST_BITS_PER_DOUBLE_INT);
>  
>        if (ch)
>  	ch = (unsigned char) str[i];
> -      c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
> +      c.elt_ref (j / HOST_BITS_PER_WIDE_INT) |= ch << (j % HOST_BITS_PER_WIDE_INT);

Long line.

> @@ -4990,12 +4996,13 @@ expand_builtin_signbit (tree exp, rtx target)
>  
>    if (bitpos < GET_MODE_BITSIZE (rmode))
>      {
> -      double_int mask = double_int_zero.set_bit (bitpos);
> +      wide_int mask;
> +      mask = wide_int::set_bit_in_zero (bitpos, rmode);

No real point splitting this.

> @@ -1511,17 +1511,20 @@ Similarly, there is only one object for the integer whose value is
>  
>  @findex const_double
>  @item (const_double:@var{m} @var{i0} @var{i1} @dots{})
> -Represents either a floating-point constant of mode @var{m} or an
> -integer constant too large to fit into @code{HOST_BITS_PER_WIDE_INT}
> -bits but small enough to fit within twice that number of bits (GCC
> -does not provide a mechanism to represent even larger constants).  In
> -the latter case, @var{m} will be @code{VOIDmode}.  For integral values
> -constants for modes with more bits than twice the number in
> -@code{HOST_WIDE_INT} the implied high order bits of that constant are
> -copies of the top bit of @code{CONST_DOUBLE_HIGH}.  Note however that
> -integral values are neither inherently signed nor inherently unsigned;
> -where necessary, signedness is determined by the rtl operation
> -instead.
> +On older ports, this represents either a floating-point constant of
> +mode @var{m} or an integer constant too large to fit into
> +@code{HOST_BITS_PER_WIDE_INT} bits but small enough to fit within
> +twice that number of bits (GCC does not provide a mechanism to
> +represent even larger constants).

No longer true :-)

>[...] In the latter case, @var{m} will be
> +@code{VOIDmode}.  For integral values constants for modes with more
> +bits than twice the number in @code{HOST_WIDE_INT} the implied high
> +order bits of that constant are copies of the top bit of
> +@code{CONST_DOUBLE_HIGH}.  Note however that integral values are
> +neither inherently signed nor inherently unsigned; where necessary,
> +signedness is determined by the rtl operation instead.
> +
> +On more modern ports, @code{CONST_DOUBLE} only represents floating
> +point values.   New ports define to TARGET_SUPPORTS_WIDE_INT to  

Truncated sentence.

> @@ -1536,6 +1539,37 @@ machine's or host machine's floating point format.  To convert them to
>  the precise bit pattern used by the target machine, use the macro
>  @code{REAL_VALUE_TO_TARGET_DOUBLE} and friends (@pxref{Data Output}).
>  
> +@findex const_wide_int
> +@item (const_wide_int:@var{m} @var{nunits} @var{elt0} @dots{})
> +This contains a garbage collected array of @code{HOST_WIDE_INTS} that
> +is large enough to hold any constant that can be represented on the
> +target.

Suggest dropping "garbage-collected".  I think it's a hold-over from
when the vector was separate.

> This form of rtl is only used on targets that define
> +@code{TARGET_SUPPORTS_WIDE_INT} to be non zero and then
> +@code{CONST_DOUBLES} are only used to hold floating point values.  If

@code{const_double}s.  In general, rtl names should be lower case
in @code{...}, and the 's' should come outside.  There are quite
a few instances (because of the detailed documenation :-)) so I won't
list them all.  But this applies to const_int and const_wide_int too.

> +The values are stored in a compressed format.   The higher order
> +0s or -1s are not represented if they are just the logical sign
> +extension the number that is represented.   

extension of ...

> +On older ports, large integers are stored in @code{CONST_DOUBLE} rtl
> +objects.  Newer ports define @code{TARGET_SUPPORTS_WIDE_INT} to be non
> +zero to indicate tha large integers are stored in

...that large integers...

> +Converting a port mostly requires looking for the places where
> +@code{CONST_DOUBLES} are used with @code{VOIDmode} and replacing that
> +code with code that accesses @code{CONST_WIDE_INT}s.  @code{"grep -i
> +const_double"} at the port level gets you to 95% of the changes that

@samp{grep -i const_double} (I think)

> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
> index 98c88f7..bcf01e7 100644
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c

As before, no comments on this.

> +/* V contains a wide_int.  A CONST_INT or CONST_WIDE_INT (if
> +   TARGET_SUPPORTS_WIDE_INT is defined) or CONST_DOUBLE if
> +   TARGET_SUPPORTS_WIDE_INT is not defined is produced based on the
> +   number of HOST_WIDE_INTs that are necessary to represent the value
> +   in compact form.  */
>  rtx
> -immed_double_int_const (double_int i, enum machine_mode mode)
> +immed_wide_int_const (const wide_int &v, enum machine_mode mode)
>  {
> -  return immed_double_const (i.low, i.high, mode);
> +  unsigned int len = v.get_len ();
> +
> +  if (len < 2)
> +    return gen_int_mode (v.elt (0), mode);
> +

I think we should have an assert here that the precision and bitsize of
the mode match those of the wide_int.

> +/* Return a constant integer (CONST_INT or CONST_WIDE_INT) mask value

Might as well drop the "(CONST_INT or CONST_WIDE_INT)".

> +   of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
> +   complement of that if COMPLEMENT.  The mask is truncated if
> +   necessary to the width of mode MODE.  The mask is zero-extended if
> +   BITSIZE+BITPOS is too small for MODE.  */
> +
> +static inline rtx 
> +mask_rtx (enum machine_mode mode, int bitpos, int bitsize, bool complement)
> +{
> +  return immed_wide_int_const 
> +    (wide_int::shifted_mask (bitpos, bitsize, complement, mode), mode);
> +}
> +
> -/* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
> -   VALUE truncated to BITSIZE bits and then shifted left BITPOS bits.  */
> +/* Return a constant integer (CONST_INT or CONST_WIDE_INT) rtx with the value
> +   VALUE truncated to BITSIZE bits and then shifted left BITPOS bits.   */
>  
>  static rtx
>  lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
>  {

Same here.

> @@ -1022,7 +1024,7 @@ expand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
>       is true when the effective shift value is less than BITS_PER_WORD.
>       Set SUPERWORD_OP1 to the shift count that should be used to shift
>       OUTOF_INPUT into INTO_TARGET when the condition is false.  */
> -  tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
> +  tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD, op1_mode), op1_mode);

Long line.

> +	wlen = (len + gs - 1)/gs;	/* Number of words needed */

Formatting.

> @@ -1145,8 +1145,61 @@ const_int_operand (rtx op, enum machine_mode mode)
>    return 1;
>  }
>  
> +#if TARGET_SUPPORTS_WIDE_INT
> +/* Returns 1 if OP is an operand that is a CONST_INT or CONST_WIDE_INT
> +   of mode MODE.  */
> +int
> +const_scalar_int_operand (rtx op, enum machine_mode mode)
> +{
> +  if (!CONST_SCALAR_INT_P (op))
> +    return 0;
> +
> +  if (mode != VOIDmode)
> +    {
> +      int prec = GET_MODE_PRECISION (mode);
> +      int bitsize = GET_MODE_BITSIZE (mode);
> +      
> +      if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
> +	return 0;

Doesn't seem to be protected by a check for CONST_WIDE_INT.

> @@ -5179,13 +4815,11 @@ static rtx
>  simplify_immed_subreg (enum machine_mode outermode, rtx op,
>  		       enum machine_mode innermode, unsigned int byte)
>  {
> -  /* We support up to 512-bit values (for V8DFmode).  */
>    enum {
> -    max_bitsize = 512,
>      value_bit = 8,
>      value_mask = (1 << value_bit) - 1
>    };
> -  unsigned char value[max_bitsize / value_bit];
> +  unsigned char value [MAX_BITSIZE_MODE_ANY_MODE/value_bit];

Formatting (original was right).

> @@ -5206,6 +4841,9 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
>    if (COMPLEX_MODE_P (outermode))
>      return NULL_RTX;
>  
> +  /* We support any size mode.  */
> +  max_bitsize = MAX (GET_MODE_BITSIZE (outermode), GET_MODE_BITSIZE (innermode));

Long line.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-09 15:10                                         ` patch to fix constant math - 4th patch - the wide-int class Kenneth Zadeck
@ 2012-10-23 14:33                                           ` Richard Biener
  2012-10-23 16:25                                             ` Kenneth Zadeck
  2012-10-23 18:10                                             ` Lawrence Crowl
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Biener @ 2012-10-23 14:33 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, rdsandiford, Lawrence Crowl

On Tue, Oct 9, 2012 at 5:09 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> This patch implements the wide-int class.    this is a more general version
> of the double-int class and is meant to be the eventual replacement for that
> class.    The use of this class removes all dependencies of the host from
> the target compiler's integer math.
>
> I have made all of the changes i agreed to in the earlier emails. In
> particular, this class internally maintains a bitsize and precision but not
> a mode.     The class now is neutral about modes and tree-types.    the
> functions that take modes or tree-types are just convenience functions that
> translate the parameters into bitsize and precision and where ever there is
> a call that takes a mode, there is a corresponding call that takes a
> tree-type.
>
> All of the little changes that richi suggested have also been made.
>
> The buffer sizes is now twice the size needed by the largest integer mode.
> This gives enough room for tree-vrp to do full multiplies on any type that
> the target supports.
>
> Tested on x86-64.
>
> This patch depends on the first three patches.   I am still waiting on final
> approval on the hwint.h patch.
>
> Ok to commit?

diff --git a/gcc/wide-int.h b/gcc/wide-int.h
new file mode 100644
index 0000000..efd2c01
--- /dev/null
+++ b/gcc/wide-int.h
...
+#ifndef GENERATOR_FILE

The whole file is guarded with that ... why?  That is bound to be fragile once
use of wide-int spreads?  How do generator programs end up including
this file if they don't need it at all?

+#include "tree.h"
+#include "hwint.h"
+#include "options.h"
+#include "tm.h"
+#include "insn-modes.h"
+#include "machmode.h"
+#include "double-int.h"
+#include <gmp.h>
+#include "insn-modes.h"
+

That's a lot of tree and rtl dependencies.  double-int.h avoids these by
placing conversion routines in different headers or by only resorting to
types in coretypes.h.  Please try to reduce the above to a minimum.

+  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];

are we sure this rounds properly?  Consider a port with max byte mode
size 4 on a 64bit host.

I still would like to have the ability to provide specializations of wide_int
for "small" sizes, thus ideally wide_int would be a template templated
on the number of HWIs in val.  Interface-wise wide_int<2> should be
identical to double_int, thus we should be able to do

typedef wide_int<2> double_int;

in double-int.h and replace its implementation with a specialization of
wide_int.  Due to a number of divergences (double_int is not a subset
of wide_int) that doesn't seem easily possible (one reason is the
ShiftOp and related enums you use).  Of course wide_int is not a
template either.  For the hypotetical embedded target above we'd
end up using wide_int<1>, a even more trivial specialization.

I realize again this wide-int is not what your wide-int is (because you
add a precision member).  Still factoring out the "common"s of
wide-int and double-int into a wide_int_raw <> template should be
possible.

+class wide_int {
+  /* Internal representation.  */
+
+  /* VAL is set to a size that is capable of computing a full
+     multiplication on the largest mode that is represented on the
+     target.  The full multiplication is use by tree-vrp.  If
+     operations are added that require larger buffers, then VAL needs
+     to be changed.  */
+  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  unsigned short len;
+  unsigned int bitsize;
+  unsigned int precision;

The len, bitsize and precision members need documentation.  At least
one sounds redundant.

+ public:
+  enum ShiftOp {
+    NONE,
NONE is never a descriptive name ... I suppose this is for arithmetic vs.
logical shifts?
+    /* There are two uses for the wide-int shifting functions.  The
+       first use is as an emulation of the target hardware.  The
+       second use is as service routines for other optimizations.  The
+       first case needs to be identified by passing TRUNC as the value
+       of ShiftOp so that shift amount is properly handled according to the
+       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
+       amount is always truncated by the bytesize of the mode of
+       THIS.  */
+    TRUNC

ah, no, it's for SHIFT_COUNT_TRUNCATED.  "mode of THIS"?  Now
it's precision I suppose.  That said, handling SHIFT_COUNT_TRUNCATED
in wide-int sounds over-engineered, the caller should be responsible
of applying SHIFT_COUNT_TRUNCATED when needed.

+  enum SignOp {
+    /* Many of the math functions produce different results depending
+       on if they are SIGNED or UNSIGNED.  In general, there are two
+       different functions, whose names are prefixed with an 'S" and
+       or an 'U'.  However, for some math functions there is also a
+       routine that does not have the prefix and takes an SignOp
+       parameter of SIGNED or UNSIGNED.  */
+    SIGNED,
+    UNSIGNED
+  };

double-int and _all_ of the rest of the middle-end uses a 'int uns' parameter
for this.  _Please_ follow that.  Otherwise if you communicate between
those interfaces you have to to uns ? UNSIGNED : SIGNED and
signop == UNSIGNED ? 1 : 0 all over the place.

+  static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize,
+                            unsigned int precision);
+  static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize,
+                            unsigned int precision, bool *overflow);

I suppose , bool *overflow = NULL would do as well?  What's the
distinction between bitsize and precision (I suppose, see the above
question)?  I suppose precision <= bitsize and bits above precision
are sign/zero extended (and the rest of the val[] array contains undefined
content?)?  But we also have 'len', which then matches bitsize (well
it may be larger).  So IMHO either bitsize or len is redundant.  At least
the tree level nowhere considers partial integer modes special this way
(only the precision is ever taken into account, but we always sign-/zero-extend
to the whole double-int - thus 'len' in wide-int terms).

+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type);
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type,
+                                  bool *overflow);

Are you needing this overload or are you adding it for "completeness"?
Because this interface is wrong(TM), and whoever calls it has at least
cleanup opportunities ... from_tree or from_rtx makes sense.

Also in which cases do you need "overflow"?  a HWI always fits in
a wide-int!  All trees and rtxen do, too.  You seem to merge two
operations here, conversion to wide-int and truncation / extension.
That doesn't look like a clean interface to me.

+  static wide_int from_double_int (enum machine_mode, double_int);

the choice of passing a mode seems arbitrary (the natural interface
would be nothing - precision is 2 * HWI).  Passing it as first parameter
is even more strange to me ;)

+  static wide_int from_tree (const_tree);
+  static wide_int from_rtx (const_rtx, enum machine_mode);

+  HOST_WIDE_INT to_shwi (unsigned int prec) const;

See above - merges two basic operations.  You should write

 w.sext (prec).to_shwi ()

instead (I _suppose_ it should sign-extend, should it? ;)).  Btw, why
don't we need to always specify bitsize together with precision in all
the places?  (not that I am arguing for it, I'm arguing for the
removal of bitsize)

+  static wide_int max_value (unsigned int bitsize, unsigned int prec,
SignOp sgn);

now that I am seeing this - is there any restriction on how the precision
of a partial integer mode may differ from its bitsize?  Can we have
POImode with 1 bit precision?  I suppose the solution for all this is
that when converting a wide-int to a RTX with a mode then we need to
zero-/sign-extend to the modes bitsize (and wide-int only cares about
precision).  Eventually a set_len can adjust the amount of BITS_PER_UNITs
we fill with meaningful values if needed.  Otherwise len == precision
/ BITS_PER_UNIT (rounded to HWI for obvious practical reasons).

+  inline static wide_int minus_one (unsigned int bitsize, unsigned int prec);
+  inline static wide_int minus_one (const_tree type);
+  inline static wide_int minus_one (enum machine_mode mode);
+  inline static wide_int zero (unsigned int bitsize, unsigned int prec);
+  inline static wide_int zero (const_tree type);
+  inline static wide_int zero (enum machine_mode mode);
+  inline static wide_int one (unsigned int bitsize, unsigned int prec);
+  inline static wide_int one (const_tree type);
+  inline static wide_int one (enum machine_mode mode);
+  inline static wide_int two (unsigned int bitsize, unsigned int prec);
+  inline static wide_int two (const_tree type);
+  inline static wide_int two (enum machine_mode mode);
+  inline static wide_int ten (unsigned int bitsize, unsigned int prec);
+  inline static wide_int ten (const_tree type);
+  inline static wide_int ten (enum machine_mode mode);

wheeee .... ;)

What's wrong with from_uhwi (10, ...)?  double-int has the above for
compatibility reasons only.  And why should I care about type/mode/size
for something as simple as '1'?

+  inline unsigned short get_len () const;
+  inline unsigned int get_bitsize () const;
+  inline unsigned int get_precision () const;
+  inline unsigned int get_full_len () const;

not sure which air you are pulling full_len from ;)

+  wide_int force_to_size (unsigned int bitsize,
+                         unsigned int precision) const;

or rather 'trunc'?  Seems to be truncation and set_len combined?

I wonder if for the various ways to specify precision/len there is a nice C++
way of moving this detail out of wide-int.  I can think only of one:

struct WIntSpec {
  WIntSpec (unsigned int len, unsigned int precision);
  WIntSpec (const_tree);
  WIntSpec (enum machine_mode);
  unsigned int len;
  unsigned int precision;
};

and then (sorry to pick one of the less useful functions):

  inline static wide_int zero (WIntSpec)

which you should be able to call like

  wide_int::zero (SImode)
  wide_int::zero (integer_type_node)

and (ugly)

  wide_int::zero (WIntSpec (32, 32))

with C++0x wide_int::zero ({32, 32}) should be possible?  Or we keep
the precision overload.  At least providing the WIntSpec abstraction
allows custom ways of specifying required bits to not pollute wide-int
itself too much.  Lawrence?

+  /* Printing functions.  */
+
+  void print_dec (char *buf, SignOp sgn) const;
+  void print_dec (FILE *file, SignOp sgn) const;
+  void print_decs (char *buf) const;
+  void print_decs (FILE *file) const;
+  void print_decu (char *buf) const;
+  void print_decu (FILE *file) const;
+  void print_hex (char *buf) const;
+  void print_hex (FILE *file) const;

consider moving them to standalone functions, out of wide-int.h

+  inline bool minus_one_p () const;
+  inline bool zero_p () const;
+  inline bool one_p () const;
+  inline bool neg_p () const;

what's wrong with w == -1, w == 0, w == 1, etc.?

+  bool only_sign_bit_p (unsigned int prec) const;
+  bool only_sign_bit_p () const;

what's that?  Some of the less obvious functions should be documented
in the header I think.  Smells of combining two things again here.
Either wide-int has an intrinsic precision or it has not ... (like double-int).

+  bool fits_u_p (unsigned int prec) const;
+  bool fits_s_p (unsigned int prec) const;

See above.

+  /* Extension  */
+
+  inline wide_int ext (unsigned int offset, SignOp sgn) const;
+  wide_int sext (unsigned int offset) const;
+  wide_int sext (enum machine_mode mode) const;
+  wide_int zext (unsigned int offset) const;
+  wide_int zext (enum machine_mode mode) const;

'offset'?  I suppose that's 'precision'.  Does that alter the
precision of *this?
I think it should (and thus there should be no set_precision function).
If it doesn't alter precision the functions don't make much sense to me.

+  wide_int set_bit (unsigned int bitpos) const;

this kind of interface is strange.  You call it like w.set_bit (1) but it
doesn't actually set bit 1 in w but it constructs a new wide_int and
returns that.  So I suppose it should be

  wide_int with_bit_set (unsigned int bitpos) const;

or similar.  Or simply have a mutating set_bit.  Or leave it out entierly,
we cannot have many uses of this kind of weird interface.

similar comments for the rest.

.... rest skipped ...

+                                   / HOST_BITS_PER_WIDE_INT + 32));
+  char *dump (char* buf) const;
+ private:
+
+  /* Private utility routines.  */
+  wide_int decompress (unsigned int target, unsigned int bitsize,
+                      unsigned int precision) const;
+  static wide_int add_overflow (const wide_int *op0, const wide_int *op1,
+                               wide_int::SignOp sgn, bool *overflow);
+  static wide_int sub_overflow (const wide_int *op0, const wide_int *op1,
+                               wide_int::SignOp sgn, bool *overflow);
+};


IMHO way too many functions for a well tested initial implementation.
There are a lot of things that seem operation compositions.  Is your
concern efficiency here?  That would be bad as that means wide_ints
are too heavy weight.

Can you use gcov to see which functions have (how much) coverage?

Thanks,
Richard.



> kenny
>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-23 14:33                                           ` Richard Biener
@ 2012-10-23 16:25                                             ` Kenneth Zadeck
  2012-10-23 18:52                                               ` Lawrence Crowl
  2012-10-24 10:10                                               ` Richard Biener
  2012-10-23 18:10                                             ` Lawrence Crowl
  1 sibling, 2 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-23 16:25 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, rdsandiford, Lawrence Crowl


On 10/23/2012 10:12 AM, Richard Biener wrote:
> On Tue, Oct 9, 2012 at 5:09 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> This patch implements the wide-int class.    this is a more general version
>> of the double-int class and is meant to be the eventual replacement for that
>> class.    The use of this class removes all dependencies of the host from
>> the target compiler's integer math.
>>
>> I have made all of the changes i agreed to in the earlier emails. In
>> particular, this class internally maintains a bitsize and precision but not
>> a mode.     The class now is neutral about modes and tree-types.    the
>> functions that take modes or tree-types are just convenience functions that
>> translate the parameters into bitsize and precision and where ever there is
>> a call that takes a mode, there is a corresponding call that takes a
>> tree-type.
>>
>> All of the little changes that richi suggested have also been made.
>>
>> The buffer sizes is now twice the size needed by the largest integer mode.
>> This gives enough room for tree-vrp to do full multiplies on any type that
>> the target supports.
>>
>> Tested on x86-64.
>>
>> This patch depends on the first three patches.   I am still waiting on final
>> approval on the hwint.h patch.
>>
>> Ok to commit?
> diff --git a/gcc/wide-int.h b/gcc/wide-int.h
> new file mode 100644
> index 0000000..efd2c01
> --- /dev/null
> +++ b/gcc/wide-int.h
> ...
> +#ifndef GENERATOR_FILE

> The whole file is guarded with that ... why?  That is bound to be fragile once
> use of wide-int spreads?  How do generator programs end up including
> this file if they don't need it at all?
This is so that wide-int can be included at the level of the 
generators.   There some stuff that needs to see this type that is done 
during the build build phase that cannot see the types that are included 
in wide-int.h.
> +#include "tree.h"
> +#include "hwint.h"
> +#include "options.h"
> +#include "tm.h"
> +#include "insn-modes.h"
> +#include "machmode.h"
> +#include "double-int.h"
> +#include <gmp.h>
> +#include "insn-modes.h"
> +
>
> That's a lot of tree and rtl dependencies.  double-int.h avoids these by
> placing conversion routines in different headers or by only resorting to
> types in coretypes.h.  Please try to reduce the above to a minimum.
>
> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
>
> are we sure this rounds properly?  Consider a port with max byte mode
> size 4 on a 64bit host.
I do not believe that this can happen.   The core compiler includes all 
modes up to TI mode, so by default we already up to 128 bits.
> I still would like to have the ability to provide specializations of wide_int
> for "small" sizes, thus ideally wide_int would be a template templated
> on the number of HWIs in val.  Interface-wise wide_int<2> should be
> identical to double_int, thus we should be able to do
>
> typedef wide_int<2> double_int;
If you want to go down this path after the patches get in, go for it.    
I see no use at all for this.
This was not meant to be a plug in replacement for double int. This goal 
of this patch is to get the compiler to do the constant math the way 
that the target does it.   Any such instantiation is by definition 
placing some predefined limit that some target may not want.

> in double-int.h and replace its implementation with a specialization of
> wide_int.  Due to a number of divergences (double_int is not a subset
> of wide_int) that doesn't seem easily possible (one reason is the
> ShiftOp and related enums you use).  Of course wide_int is not a
> template either.  For the hypotetical embedded target above we'd
> end up using wide_int<1>, a even more trivial specialization.
>
> I realize again this wide-int is not what your wide-int is (because you
> add a precision member).  Still factoring out the "common"s of
> wide-int and double-int into a wide_int_raw <> template should be
> possible.
>
> +class wide_int {
> +  /* Internal representation.  */
> +
> +  /* VAL is set to a size that is capable of computing a full
> +     multiplication on the largest mode that is represented on the
> +     target.  The full multiplication is use by tree-vrp.  If
> +     operations are added that require larger buffers, then VAL needs
> +     to be changed.  */
> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
> +  unsigned short len;
> +  unsigned int bitsize;
> +  unsigned int precision;
>
> The len, bitsize and precision members need documentation.  At least
> one sounds redundant.
>
> + public:
> +  enum ShiftOp {
> +    NONE,
> NONE is never a descriptive name ... I suppose this is for arithmetic vs.
> logical shifts?
suggest something
> +    /* There are two uses for the wide-int shifting functions.  The
> +       first use is as an emulation of the target hardware.  The
> +       second use is as service routines for other optimizations.  The
> +       first case needs to be identified by passing TRUNC as the value
> +       of ShiftOp so that shift amount is properly handled according to the
> +       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
> +       amount is always truncated by the bytesize of the mode of
> +       THIS.  */
> +    TRUNC
>
> ah, no, it's for SHIFT_COUNT_TRUNCATED.  "mode of THIS"?  Now
> it's precision I suppose.  That said, handling SHIFT_COUNT_TRUNCATED
> in wide-int sounds over-engineered, the caller should be responsible
> of applying SHIFT_COUNT_TRUNCATED when needed.
I am fighting all of the modes out.   i will update this patch with more 
cleanups
> +  enum SignOp {
> +    /* Many of the math functions produce different results depending
> +       on if they are SIGNED or UNSIGNED.  In general, there are two
> +       different functions, whose names are prefixed with an 'S" and
> +       or an 'U'.  However, for some math functions there is also a
> +       routine that does not have the prefix and takes an SignOp
> +       parameter of SIGNED or UNSIGNED.  */
> +    SIGNED,
> +    UNSIGNED
> +  };
>
> double-int and _all_ of the rest of the middle-end uses a 'int uns' parameter
> for this.  _Please_ follow that.  Otherwise if you communicate between
> those interfaces you have to to uns ? UNSIGNED : SIGNED and
> signop == UNSIGNED ? 1 : 0 all over the place.
I really do not want to.   What i discovered is that some places in the 
compiler do and some places do not and some places take the reverse 
convention  MNEMONIC is better than NUMERIC.
>
> +  static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize,
> +                            unsigned int precision);
> +  static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize,
> +                            unsigned int precision, bool *overflow);
>
> I suppose , bool *overflow = NULL would do as well?  What's the
> distinction between bitsize and precision (I suppose, see the above
> question)?  I suppose precision <= bitsize and bits above precision
> are sign/zero extended (and the rest of the val[] array contains undefined
> content?)?  But we also have 'len', which then matches bitsize (well
> it may be larger).  So IMHO either bitsize or len is redundant.  At least
> the tree level nowhere considers partial integer modes special this way
> (only the precision is ever taken into account, but we always sign-/zero-extend
> to the whole double-int - thus 'len' in wide-int terms).
Some operations, mostly shifting, needs  both the bitsize and 
precision.   In the early days of the compiler, people pretty much 
ignored the precision and most of the compiler math was done using the 
bitsize.   This made it very painful for the people who supported ports 
that had odd sized modes.   Bernd has been cleaning this up at the rtl 
level and the first 5 patches move that forward.   But you really do 
need both.


> +  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type);
> +  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type,
> +                                  bool *overflow);
>
> Are you needing this overload or are you adding it for "completeness"?
> Because this interface is wrong(TM), and whoever calls it has at least
> cleanup opportunities ... from_tree or from_rtx makes sense.
the functions are actually quite different.    in general overflow 
checking at least doubles the cost of implementation and sometimes it is 
much greater.   Having them be separate cleans up the implementation.


>
> Also in which cases do you need "overflow"?  a HWI always fits in
> a wide-int!  All trees and rtxen do, too.  You seem to merge two
> operations here, conversion to wide-int and truncation / extension.
> That doesn't look like a clean interface to me.
This is the big difference between double_int and wide_int:    I do not 
care if it fits in the underlying representation, i care if it fits in 
the precision of the type.   If the type is for a char and the value is 
100000, overflow is set.   In general setting overflow in the wide-int 
interface means something very different from double-int interface.    A 
large number of places that check for overflow with double in do not 
need to check it for wide int.

> +  static wide_int from_double_int (enum machine_mode, double_int);
>
> the choice of passing a mode seems arbitrary (the natural interface
> would be nothing - precision is 2 * HWI).  Passing it as first parameter
> is even more strange to me ;)
the first part of the question is answered above.   the second part of 
the question was fixed on my private tree a few days ago and will get 
pushed out.
> +  static wide_int from_tree (const_tree);
> +  static wide_int from_rtx (const_rtx, enum machine_mode);
>
> +  HOST_WIDE_INT to_shwi (unsigned int prec) const;
>
> See above - merges two basic operations.  You should write
>
>   w.sext (prec).to_shwi ()
>
> instead (I _suppose_ it should sign-extend, should it? ;)).  Btw, why
> don't we need to always specify bitsize together with precision in all
> the places?  (not that I am arguing for it, I'm arguing for the
> removal of bitsize)
because the bitsize and precision are part of the representation of the 
value.    You only have to specify them on the way into wide-int or if 
you need to change them (this is rare but it does happen).
> +  static wide_int max_value (unsigned int bitsize, unsigned int prec,
> SignOp sgn);
>
> now that I am seeing this - is there any restriction on how the precision
> of a partial integer mode may differ from its bitsize?  Can we have
> POImode with 1 bit precision?  I suppose the solution for all this is
> that when converting a wide-int to a RTX with a mode then we need to
> zero-/sign-extend to the modes bitsize (and wide-int only cares about
> precision).  Eventually a set_len can adjust the amount of BITS_PER_UNITs
> we fill with meaningful values if needed.  Otherwise len == precision
> / BITS_PER_UNIT (rounded to HWI for obvious practical reasons).
the precision must be less than or equal to the bitsize.   That is the 
only restriction.
I do not know if you can have poi1?    Every case that i have seen, the 
partial int is a partial of the next largest power of 2 mode. But there 
is nothing in wide-int that cares about this.

>
> +  inline static wide_int minus_one (unsigned int bitsize, unsigned int prec);
> +  inline static wide_int minus_one (const_tree type);
> +  inline static wide_int minus_one (enum machine_mode mode);
> +  inline static wide_int zero (unsigned int bitsize, unsigned int prec);
> +  inline static wide_int zero (const_tree type);
> +  inline static wide_int zero (enum machine_mode mode);
> +  inline static wide_int one (unsigned int bitsize, unsigned int prec);
> +  inline static wide_int one (const_tree type);
> +  inline static wide_int one (enum machine_mode mode);
> +  inline static wide_int two (unsigned int bitsize, unsigned int prec);
> +  inline static wide_int two (const_tree type);
> +  inline static wide_int two (enum machine_mode mode);
> +  inline static wide_int ten (unsigned int bitsize, unsigned int prec);
> +  inline static wide_int ten (const_tree type);
> +  inline static wide_int ten (enum machine_mode mode);
>
> wheeee .... ;)
yes, and they are all used.
> What's wrong with from_uhwi (10, ...)?  double-int has the above for
> compatibility reasons only.  And why should I care about type/mode/size
> for something as simple as '1'?
the 10 is an interesting case.   at least in my patches it is not used, 
but i had put it in because i started from double-int and it has it.   
However, i believe in fat api's if something gets used a lot, then it 
should be part of the api.    all of them except for 10 are used a lot.

I will point out than in my original patch, these were just macros that 
expanded into from_uhwi, but richi wanted them to be real functions.



> +  inline unsigned short get_len () const;
> +  inline unsigned int get_bitsize () const;
> +  inline unsigned int get_precision () const;
> +  inline unsigned int get_full_len () const;
>
> not sure which air you are pulling full_len from ;)
when you need it, you need it.   the dwarf writer really needs it, 
because it wants to see all of the words on a multiword value, not just 
the ones that "need" to be represented so that it is easy to read.

I have a big comment on when not to use this in my tree.
> +  wide_int force_to_size (unsigned int bitsize,
> +                         unsigned int precision) const;
>
> or rather 'trunc'?  Seems to be truncation and set_len combined?
why do you think it is only shortening it?
>
> I wonder if for the various ways to specify precision/len there is a nice C++
> way of moving this detail out of wide-int.  I can think only of one:
>
> struct WIntSpec {
>    WIntSpec (unsigned int len, unsigned int precision);
>    WIntSpec (const_tree);
>    WIntSpec (enum machine_mode);
>    unsigned int len;
>    unsigned int precision;
> };
>
> and then (sorry to pick one of the less useful functions):
>
>    inline static wide_int zero (WIntSpec)
It depends on what you have available in your hands when you need to 
call a function.   At the rtl level we almost never have tree types, but 
we have modes.    At the tree level, you almost never have modes.    In 
general the convenience functions take anything and just extract the 
prec and bitsize for you.    But there are several places that need to 
specify the prec and bitsize and so these are now the base primitives.
> which you should be able to call like
>
>    wide_int::zero (SImode)
>    wide_int::zero (integer_type_node)
>
> and (ugly)
>
>    wide_int::zero (WIntSpec (32, 32))
>
> with C++0x wide_int::zero ({32, 32}) should be possible?  Or we keep
> the precision overload.  At least providing the WIntSpec abstraction
> allows custom ways of specifying required bits to not pollute wide-int
> itself too much.  Lawrence?
>
> +  /* Printing functions.  */
> +
> +  void print_dec (char *buf, SignOp sgn) const;
> +  void print_dec (FILE *file, SignOp sgn) const;
> +  void print_decs (char *buf) const;
> +  void print_decs (FILE *file) const;
> +  void print_decu (char *buf) const;
> +  void print_decu (FILE *file) const;
> +  void print_hex (char *buf) const;
> +  void print_hex (FILE *file) const;
>
> consider moving them to standalone functions, out of wide-int.h
I do not see much reason to do this.    They use the internals of 
wide-int and moving them somewhere else is just exposing the internals 
for no real reason.
>
> +  inline bool minus_one_p () const;
> +  inline bool zero_p () const;
> +  inline bool one_p () const;
> +  inline bool neg_p () const;
>
> what's wrong with w == -1, w == 0, w == 1, etc.?
I would love to do this and you seem to be somewhat knowledgeable of 
c++.   But i cannot for the life of me figure out how to do it.

say i have a TImode number, which must be represented in 4 ints on a 32 
bit host (the same issue happens on 64 bit hosts, but the examples are 
simpler on 32 bit hosts) and i compare it to -1.    The value that i am 
going to see as the argument of the function is going have the value 
0xffffffff.
but the value that i have internally is 128 bits.   do i take this and 0 
or sign extend it?   in particular if someone wants to compare a number 
to 0xdeadbeef  i have no idea what to do.   I tried defining two 
different functions, one that took a signed and one that took and 
unsigned number but then i wanted a cast in front of all the positive 
numbers.

If there is a way to do this, then i will do it, but it is going to have 
to work properly for things larger than a HOST_WIDE_INT.

I know that double-int does some of this and it does not carry around a 
notion of signedness either.   is this just code that has not been fully 
tested or is there a trick in c++ that i am missing?

> +  bool only_sign_bit_p (unsigned int prec) const;
> +  bool only_sign_bit_p () const;
>
> what's that?  Some of the less obvious functions should be documented
> in the header I think.  Smells of combining two things again here.
> Either wide-int has an intrinsic precision or it has not ... (like double-int).

Again, i have put in things that are useful, it is all driven from what 
the clients need.    This is done all over the back end.
>
> +  bool fits_u_p (unsigned int prec) const;
> +  bool fits_s_p (unsigned int prec) const;
>
> See above.
>
> +  /* Extension  */
> +
> +  inline wide_int ext (unsigned int offset, SignOp sgn) const;
> +  wide_int sext (unsigned int offset) const;
> +  wide_int sext (enum machine_mode mode) const;
> +  wide_int zext (unsigned int offset) const;
> +  wide_int zext (enum machine_mode mode) const;
>
> 'offset'?  I suppose that's 'precision'.  Does that alter the
> precision of *this?
> I think it should (and thus there should be no set_precision function).
> If it doesn't alter precision the functions don't make much sense to me.
The ones that alter the precision take a precision and bitsize, the ones 
that just want do the extension from some place and end up with a bit 
pattern that looks a certain way take the offset.

> +  wide_int set_bit (unsigned int bitpos) const;
>
> this kind of interface is strange.  You call it like w.set_bit (1) but it
> doesn't actually set bit 1 in w but it constructs a new wide_int and
> returns that.  So I suppose it should be
>
>    wide_int with_bit_set (unsigned int bitpos) const;
the interface is pure.    if you want me to change the name, that is fine.
>
> or similar.  Or simply have a mutating set_bit.  Or leave it out entierly,
> we cannot have many uses of this kind of weird interface.
>
> similar comments for the rest.
>
> .... rest skipped ...
>
> +                                   / HOST_BITS_PER_WIDE_INT + 32));
> +  char *dump (char* buf) const;
> + private:
> +
> +  /* Private utility routines.  */
> +  wide_int decompress (unsigned int target, unsigned int bitsize,
> +                      unsigned int precision) const;
> +  static wide_int add_overflow (const wide_int *op0, const wide_int *op1,
> +                               wide_int::SignOp sgn, bool *overflow);
> +  static wide_int sub_overflow (const wide_int *op0, const wide_int *op1,
> +                               wide_int::SignOp sgn, bool *overflow);
> +};
>
>
> IMHO way too many functions for a well tested initial implementation.
> There are a lot of things that seem operation compositions.  Is your
> concern efficiency here?  That would be bad as that means wide_ints
> are too heavy weight.
There are two sides of ease of use, you can force people to write out 
everything using a few primitives or you give them a rich interface.    
I come from the rich interface school.

If i was just going out and selling a new interface, something clean and 
small would be easier to sell.   However, that is not what i am 
doing.    I have converted substantially the entire back end to this and 
in the next few days i will submit patches that do the tree level.   So 
i am a big user and a rich api makes that conversion much easier.

Remember that these patches are not syntactic changes like the 
conversion of double-int to use c++ interfaces.    I am actually 
converting most of the code that only does transformations if the value 
fits in some fixed number of HWIs to work at the targets precision.   My 
motivation is that GCC does not actually work correctly with larger 
types.   I will do what it takes to get these patches in an acceptable 
form to the api police but my motivations is that the compiler is now 
neither correct nor robust with 128 bit types and above.

kenny

> Can you use gcov to see which functions have (how much) coverage?
>
> Thanks,
> Richard.
>
>
>
>> kenny
>>
>>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-23 14:33                                           ` Richard Biener
  2012-10-23 16:25                                             ` Kenneth Zadeck
@ 2012-10-23 18:10                                             ` Lawrence Crowl
  1 sibling, 0 replies; 217+ messages in thread
From: Lawrence Crowl @ 2012-10-23 18:10 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kenneth Zadeck, Mike Stump, gcc-patches, rdsandiford

On 10/23/12, Richard Biener <richard.guenther@gmail.com> wrote:
> I wonder if for the various ways to specify precision/len there
> is a nice C++ way of moving this detail out of wide-int.  I can
> think only of one:
>
> struct WIntSpec {
>   WIntSpec (unsigned int len, unsigned int precision);
>   WIntSpec (const_tree);
>   WIntSpec (enum machine_mode);
>   unsigned int len;
>   unsigned int precision;
> };
>
> and then (sorry to pick one of the less useful functions):
>
>   inline static wide_int zero (WIntSpec)
>
> which you should be able to call like
>
>   wide_int::zero (SImode)
>   wide_int::zero (integer_type_node)
>
> and (ugly)
>
>   wide_int::zero (WIntSpec (32, 32))
>
> with C++0x wide_int::zero ({32, 32}) should be possible?  Or we
> keep the precision overload.  At least providing the WIntSpec
> abstraction allows custom ways of specifying required bits to
> not pollute wide-int itself too much.  Lawrence?

Yes, in C++11, wide_int::zero ({32, 32}) is possible using an
implicit conversion to WIntSpec from an initializer_list.  However,
at present we are limited to C++03 to enable older compilers as
boot compilers.

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-23 16:25                                             ` Kenneth Zadeck
@ 2012-10-23 18:52                                               ` Lawrence Crowl
  2012-10-23 19:27                                                 ` Kenneth Zadeck
  2012-10-24 10:10                                               ` Richard Biener
  1 sibling, 1 reply; 217+ messages in thread
From: Lawrence Crowl @ 2012-10-23 18:52 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Richard Biener, Mike Stump, gcc-patches, rdsandiford

On 10/23/12, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> On 10/23/2012 10:12 AM, Richard Biener wrote:
> > +  inline bool minus_one_p () const;
> > +  inline bool zero_p () const;
> > +  inline bool one_p () const;
> > +  inline bool neg_p () const;
> >
> > what's wrong with w == -1, w == 0, w == 1, etc.?
>
> I would love to do this and you seem to be somewhat knowledgeable
> of c++.  But i cannot for the life of me figure out how to do it.

Starting from the simple case, you write an operator ==.

as global operator:  bool operator == (wide_int w, int i);
as member operator:  bool wide_int::operator == (int i);

In the simple case,

bool operator == (wide_int w, int i)
{
  switch (i)
    {
      case -1: return w.minus_one_p ();
      case  0: return w.zero_p ();
      case  1: return w.one_p ();
      default: unexpected....
    }
}

> say i have a TImode number, which must be represented in 4 ints
> on a 32 bit host (the same issue happens on 64 bit hosts, but
> the examples are simpler on 32 bit hosts) and i compare it to -1.
> The value that i am going to see as the argument of the function
> is going have the value 0xffffffff.  but the value that i have
> internally is 128 bits.  do i take this and 0 or sign extend it?

What would you have done with w.minus_one_p ()?

> in particular if someone wants to compare a number to 0xdeadbeef i
> have no idea what to do.  I tried defining two different functions,
> one that took a signed and one that took and unsigned number but
> then i wanted a cast in front of all the positive numbers.

This is where it does get tricky.  For signed arguments, you should sign
extend.  For unsigned arguments, you should not.  At present, we need
multiple overloads to avoid type ambiguities.

bool operator == (wide_int w, long long int i);
bool operator == (wide_int w, unsigned long long int i);
inline bool operator == (wide_int w, long int i)
  { return w == (long long int) i; }
inline bool operator (wide_int w, unsigned long int i)
  { return w == (unsigned long long int) i; }
inline bool operator == (wide_int w, int i)
  { return w == (long long int) i; }
inline bool operator (wide_int w, unsigned int i)
  { return w == (unsigned long long int) i; }

(There is a proposal before the C++ committee to fix this problem.)

Even so, there is room for potential bugs when wide_int does not
carry around whether or not it is signed.  The problem is that
regardless of what the programmer thinks of the sign of the wide int,
the comparison will use the sign of the int.

> If there is a way to do this, then i will do it, but it is going
> to have to work properly for things larger than a HOST_WIDE_INT.

The long-term solution, IMHO, is to either carry the sign information
around in either the type or the class data.  (I prefer type, but
with a mechanism to carry it as data when needed.)  Such comparisons
would then require consistency in signedness between the wide int
and the plain int.

> I know that double-int does some of this and it does not carry
> around a notion of signedness either.  is this just code that has
> not been fully tested or is there a trick in c++ that i am missing?

The double int class only provides == and !=, and only with other
double ints.  Otherwise, it has the same value query functions that
you do above.  In the case of double int, the goal was to simplify
use of the existing semantics.  If you are changing the semantics,
consider incorporating sign explicitly.

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-23 18:52                                               ` Lawrence Crowl
@ 2012-10-23 19:27                                                 ` Kenneth Zadeck
  2012-10-23 20:51                                                   ` Lawrence Crowl
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-23 19:27 UTC (permalink / raw)
  To: Lawrence Crowl; +Cc: Richard Biener, Mike Stump, gcc-patches, rdsandiford


On 10/23/2012 02:38 PM, Lawrence Crowl wrote:
> On 10/23/12, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>> +  inline bool minus_one_p () const;
>>> +  inline bool zero_p () const;
>>> +  inline bool one_p () const;
>>> +  inline bool neg_p () const;
>>>
>>> what's wrong with w == -1, w == 0, w == 1, etc.?
>> I would love to do this and you seem to be somewhat knowledgeable
>> of c++.  But i cannot for the life of me figure out how to do it.
> Starting from the simple case, you write an operator ==.
>
> as global operator:  bool operator == (wide_int w, int i);
> as member operator:  bool wide_int::operator == (int i);
>
> In the simple case,
>
> bool operator == (wide_int w, int i)
> {
>    switch (i)
>      {
>        case -1: return w.minus_one_p ();
>        case  0: return w.zero_p ();
>        case  1: return w.one_p ();
>        default: unexpected....
>      }
> }
>
no, this seems wrong.    you do not want to write code that can only 
fail at runtime unless there is a damn good reason to do that.
>> say i have a TImode number, which must be represented in 4 ints
>> on a 32 bit host (the same issue happens on 64 bit hosts, but
>> the examples are simpler on 32 bit hosts) and i compare it to -1.
>> The value that i am going to see as the argument of the function
>> is going have the value 0xffffffff.  but the value that i have
>> internally is 128 bits.  do i take this and 0 or sign extend it?
> What would you have done with w.minus_one_p ()?
the code "knows" that -1 is a negative number and it knows the precision 
of w.    That is enough information.   So it logically builds a -1 that 
has enough bits to do the conversion.


>> in particular if someone wants to compare a number to 0xdeadbeef i
>> have no idea what to do.  I tried defining two different functions,
>> one that took a signed and one that took and unsigned number but
>> then i wanted a cast in front of all the positive numbers.
> This is where it does get tricky.  For signed arguments, you should sign
> extend.  For unsigned arguments, you should not.  At present, we need
> multiple overloads to avoid type ambiguities.
>
> bool operator == (wide_int w, long long int i);
> bool operator == (wide_int w, unsigned long long int i);
> inline bool operator == (wide_int w, long int i)
>    { return w == (long long int) i; }
> inline bool operator (wide_int w, unsigned long int i)
>    { return w == (unsigned long long int) i; }
> inline bool operator == (wide_int w, int i)
>    { return w == (long long int) i; }
> inline bool operator (wide_int w, unsigned int i)
>    { return w == (unsigned long long int) i; }
>
> (There is a proposal before the C++ committee to fix this problem.)
>
> Even so, there is room for potential bugs when wide_int does not
> carry around whether or not it is signed.  The problem is that
> regardless of what the programmer thinks of the sign of the wide int,
> the comparison will use the sign of the int.
when they do we can revisit this.   but i looked at this and i said the 
potential bugs were not worth the effort.
>
>> If there is a way to do this, then i will do it, but it is going
>> to have to work properly for things larger than a HOST_WIDE_INT.
> The long-term solution, IMHO, is to either carry the sign information
> around in either the type or the class data.  (I prefer type, but
> with a mechanism to carry it as data when needed.)  Such comparisons
> would then require consistency in signedness between the wide int
> and the plain int.
carrying the sign information is a non starter.    The rtl level does 
not have it and the middle end violates it more often than not.    My 
view was to design this having looked at all of the usage.   I have 
basically converted the whole compiler before i released the abi.   I am 
still getting out the errors and breaking it up in reviewable sized 
patches, but i knew very very well who my clients were before i wrote 
the abi.
>
>> I know that double-int does some of this and it does not carry
>> around a notion of signedness either.  is this just code that has
>> not been fully tested or is there a trick in c++ that i am missing?
> The double int class only provides == and !=, and only with other
> double ints.  Otherwise, it has the same value query functions that
> you do above.  In the case of double int, the goal was to simplify
> use of the existing semantics.  If you are changing the semantics,
> consider incorporating sign explicitly.
>
i have, and it does not work.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-23 19:27                                                 ` Kenneth Zadeck
@ 2012-10-23 20:51                                                   ` Lawrence Crowl
  2012-10-23 21:34                                                     ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Lawrence Crowl @ 2012-10-23 20:51 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Richard Biener, Mike Stump, gcc-patches, rdsandiford

On 10/23/12, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> On 10/23/2012 02:38 PM, Lawrence Crowl wrote:
>> On 10/23/12, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>> +  inline bool minus_one_p () const;
>>>> +  inline bool zero_p () const;
>>>> +  inline bool one_p () const;
>>>> +  inline bool neg_p () const;
>>>>
>>>> what's wrong with w == -1, w == 0, w == 1, etc.?
>>> I would love to do this and you seem to be somewhat knowledgeable
>>> of c++.  But i cannot for the life of me figure out how to do it.
>> Starting from the simple case, you write an operator ==.
>>
>> as global operator:  bool operator == (wide_int w, int i);
>> as member operator:  bool wide_int::operator == (int i);
>>
>> In the simple case,
>>
>> bool operator == (wide_int w, int i)
>> {
>>    switch (i)
>>      {
>>        case -1: return w.minus_one_p ();
>>        case  0: return w.zero_p ();
>>        case  1: return w.one_p ();
>>        default: unexpected....
>>      }
>> }
>
> no, this seems wrong.    you do not want to write code that can only
> fail at runtime unless there is a damn good reason to do that.

Well, that's because it's the oversimplified case.  :-)

>>> say i have a TImode number, which must be represented in 4 ints
>>> on a 32 bit host (the same issue happens on 64 bit hosts, but
>>> the examples are simpler on 32 bit hosts) and i compare it to -1.
>>> The value that i am going to see as the argument of the function
>>> is going have the value 0xffffffff.  but the value that i have
>>> internally is 128 bits.  do i take this and 0 or sign extend it?
>>
>> What would you have done with w.minus_one_p ()?
>
> the code "knows" that -1 is a negative number and it knows the
> precision of w.  That is enough information.  So it logically
> builds a -1 that has enough bits to do the conversion.

And the code could also know that '-n' is a negative number and do
the identical conversion.  It would certainly be more difficult to
write and get all the edge cases.

>>> in particular if someone wants to compare a number to 0xdeadbeef i
>>> have no idea what to do.  I tried defining two different functions,
>>> one that took a signed and one that took and unsigned number but
>>> then i wanted a cast in front of all the positive numbers.
>> This is where it does get tricky.  For signed arguments, you should sign
>> extend.  For unsigned arguments, you should not.  At present, we need
>> multiple overloads to avoid type ambiguities.
>>
>> bool operator == (wide_int w, long long int i);
>> bool operator == (wide_int w, unsigned long long int i);
>> inline bool operator == (wide_int w, long int i)
>>    { return w == (long long int) i; }
>> inline bool operator (wide_int w, unsigned long int i)
>>    { return w == (unsigned long long int) i; }
>> inline bool operator == (wide_int w, int i)
>>    { return w == (long long int) i; }
>> inline bool operator (wide_int w, unsigned int i)
>>    { return w == (unsigned long long int) i; }
>>
>> (There is a proposal before the C++ committee to fix this problem.)
>>
>> Even so, there is room for potential bugs when wide_int does not
>> carry around whether or not it is signed.  The problem is that
>> regardless of what the programmer thinks of the sign of the wide int,
>> the comparison will use the sign of the int.
>
> when they do we can revisit this.   but i looked at this and i said the
> potential bugs were not worth the effort.

I won't disagree.  I was answering what I thought were questions on
what was possible.

>>> If there is a way to do this, then i will do it, but it is going
>>> to have to work properly for things larger than a HOST_WIDE_INT.
>> The long-term solution, IMHO, is to either carry the sign information
>> around in either the type or the class data.  (I prefer type, but
>> with a mechanism to carry it as data when needed.)  Such comparisons
>> would then require consistency in signedness between the wide int
>> and the plain int.
>
> carrying the sign information is a non starter.    The rtl level does
> not have it and the middle end violates it more often than not.    My
> view was to design this having looked at all of the usage.   I have
> basically converted the whole compiler before i released the abi.   I am
> still getting out the errors and breaking it up in reviewable sized
> patches, but i knew very very well who my clients were before i wrote
> the abi.

Okay.

>>> I know that double-int does some of this and it does not carry
>>> around a notion of signedness either.  is this just code that has
>>> not been fully tested or is there a trick in c++ that i am missing?
>> The double int class only provides == and !=, and only with other
>> double ints.  Otherwise, it has the same value query functions that
>> you do above.  In the case of double int, the goal was to simplify
>> use of the existing semantics.  If you are changing the semantics,
>> consider incorporating sign explicitly.
>
> i have, and it does not work.

Unfortunate.

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-23 20:51                                                   ` Lawrence Crowl
@ 2012-10-23 21:34                                                     ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-23 21:34 UTC (permalink / raw)
  To: Lawrence Crowl; +Cc: Richard Biener, Mike Stump, gcc-patches, rdsandiford


On 10/23/2012 04:25 PM, Lawrence Crowl wrote:
> On 10/23/12, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> On 10/23/2012 02:38 PM, Lawrence Crowl wrote:
>>> On 10/23/12, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>> +  inline bool minus_one_p () const;
>>>>> +  inline bool zero_p () const;
>>>>> +  inline bool one_p () const;
>>>>> +  inline bool neg_p () const;
>>>>>
>>>>> what's wrong with w == -1, w == 0, w == 1, etc.?
>>>> I would love to do this and you seem to be somewhat knowledgeable
>>>> of c++.  But i cannot for the life of me figure out how to do it.
>>> Starting from the simple case, you write an operator ==.
>>>
>>> as global operator:  bool operator == (wide_int w, int i);
>>> as member operator:  bool wide_int::operator == (int i);
>>>
>>> In the simple case,
>>>
>>> bool operator == (wide_int w, int i)
>>> {
>>>     switch (i)
>>>       {
>>>         case -1: return w.minus_one_p ();
>>>         case  0: return w.zero_p ();
>>>         case  1: return w.one_p ();
>>>         default: unexpected....
>>>       }
>>> }
>> no, this seems wrong.    you do not want to write code that can only
>> fail at runtime unless there is a damn good reason to do that.
> Well, that's because it's the oversimplified case.  :-)
>
>>>> say i have a TImode number, which must be represented in 4 ints
>>>> on a 32 bit host (the same issue happens on 64 bit hosts, but
>>>> the examples are simpler on 32 bit hosts) and i compare it to -1.
>>>> The value that i am going to see as the argument of the function
>>>> is going have the value 0xffffffff.  but the value that i have
>>>> internally is 128 bits.  do i take this and 0 or sign extend it?
>>> What would you have done with w.minus_one_p ()?
>> the code "knows" that -1 is a negative number and it knows the
>> precision of w.  That is enough information.  So it logically
>> builds a -1 that has enough bits to do the conversion.
> And the code could also know that '-n' is a negative number and do
> the identical conversion.  It would certainly be more difficult to
> write and get all the edge cases.
I am not a c++ hacker.   if someone wants to go there later, we can 
investigate this.
but it seems like a can of worms right now.
>
>>>> in particular if someone wants to compare a number to 0xdeadbeef i
>>>> have no idea what to do.  I tried defining two different functions,
>>>> one that took a signed and one that took and unsigned number but
>>>> then i wanted a cast in front of all the positive numbers.
>>> This is where it does get tricky.  For signed arguments, you should sign
>>> extend.  For unsigned arguments, you should not.  At present, we need
>>> multiple overloads to avoid type ambiguities.
>>>
>>> bool operator == (wide_int w, long long int i);
>>> bool operator == (wide_int w, unsigned long long int i);
>>> inline bool operator == (wide_int w, long int i)
>>>     { return w == (long long int) i; }
>>> inline bool operator (wide_int w, unsigned long int i)
>>>     { return w == (unsigned long long int) i; }
>>> inline bool operator == (wide_int w, int i)
>>>     { return w == (long long int) i; }
>>> inline bool operator (wide_int w, unsigned int i)
>>>     { return w == (unsigned long long int) i; }
>>>
>>> (There is a proposal before the C++ committee to fix this problem.)
>>>
>>> Even so, there is room for potential bugs when wide_int does not
>>> carry around whether or not it is signed.  The problem is that
>>> regardless of what the programmer thinks of the sign of the wide int,
>>> the comparison will use the sign of the int.
>> when they do we can revisit this.   but i looked at this and i said the
>> potential bugs were not worth the effort.
> I won't disagree.  I was answering what I thought were questions on
> what was possible.
>
>>>> If there is a way to do this, then i will do it, but it is going
>>>> to have to work properly for things larger than a HOST_WIDE_INT.
>>> The long-term solution, IMHO, is to either carry the sign information
>>> around in either the type or the class data.  (I prefer type, but
>>> with a mechanism to carry it as data when needed.)  Such comparisons
>>> would then require consistency in signedness between the wide int
>>> and the plain int.
>> carrying the sign information is a non starter.    The rtl level does
>> not have it and the middle end violates it more often than not.    My
>> view was to design this having looked at all of the usage.   I have
>> basically converted the whole compiler before i released the abi.   I am
>> still getting out the errors and breaking it up in reviewable sized
>> patches, but i knew very very well who my clients were before i wrote
>> the abi.
> Okay.
>
>>>> I know that double-int does some of this and it does not carry
>>>> around a notion of signedness either.  is this just code that has
>>>> not been fully tested or is there a trick in c++ that i am missing?
>>> The double int class only provides == and !=, and only with other
>>> double ints.  Otherwise, it has the same value query functions that
>>> you do above.  In the case of double int, the goal was to simplify
>>> use of the existing semantics.  If you are changing the semantics,
>>> consider incorporating sign explicitly.
>> i have, and it does not work.
> Unfortunate.
>
There is certainly a desire here not to let the ugliness of the back end 
not drag down the tree level.   But the truth is that with respect to 
the signedness, the tree level is very dirty.  If the double int code 
had taken a type from the start, things may have been different.    But 
the truth is that sign is different than size, some of the operations do 
not care about sign and some of the transformations that we want to do 
we do need them to be done in a particular but that is not dependent on 
the sign of the type. Richi has beat me up about this but i actually 
believe that most of the time when the sign of the type does not match 
the sign of the operation, the code is actually correct.

There were heroic things done at the rtl level to find the mode (and 
therefor the bitsize and precision) since this is not stored in constant 
integers.    But doing that allows the precision and bitsize to be 
reliably stored in the wide-ints.   But both the tree and rtl levels 
would need to significantly change to put the sign in.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-23 16:25                                             ` Kenneth Zadeck
  2012-10-23 18:52                                               ` Lawrence Crowl
@ 2012-10-24 10:10                                               ` Richard Biener
  2012-10-24 17:30                                                 ` Mike Stump
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Biener @ 2012-10-24 10:10 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, rdsandiford, Lawrence Crowl

On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
>
> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>
>> On Tue, Oct 9, 2012 at 5:09 PM, Kenneth Zadeck <zadeck@naturalbridge.com>
>> wrote:
>>>
>>> This patch implements the wide-int class.    this is a more general
>>> version
>>> of the double-int class and is meant to be the eventual replacement for
>>> that
>>> class.    The use of this class removes all dependencies of the host from
>>> the target compiler's integer math.
>>>
>>> I have made all of the changes i agreed to in the earlier emails. In
>>> particular, this class internally maintains a bitsize and precision but
>>> not
>>> a mode.     The class now is neutral about modes and tree-types.    the
>>> functions that take modes or tree-types are just convenience functions
>>> that
>>> translate the parameters into bitsize and precision and where ever there
>>> is
>>> a call that takes a mode, there is a corresponding call that takes a
>>> tree-type.
>>>
>>> All of the little changes that richi suggested have also been made.
>>>
>>> The buffer sizes is now twice the size needed by the largest integer
>>> mode.
>>> This gives enough room for tree-vrp to do full multiplies on any type
>>> that
>>> the target supports.
>>>
>>> Tested on x86-64.
>>>
>>> This patch depends on the first three patches.   I am still waiting on
>>> final
>>> approval on the hwint.h patch.
>>>
>>> Ok to commit?
>>
>> diff --git a/gcc/wide-int.h b/gcc/wide-int.h
>> new file mode 100644
>> index 0000000..efd2c01
>> --- /dev/null
>> +++ b/gcc/wide-int.h
>> ...
>> +#ifndef GENERATOR_FILE
>
>
>> The whole file is guarded with that ... why?  That is bound to be fragile
>> once
>> use of wide-int spreads?  How do generator programs end up including
>> this file if they don't need it at all?
>
> This is so that wide-int can be included at the level of the generators.
> There some stuff that needs to see this type that is done during the build
> build phase that cannot see the types that are included in wide-int.h.
>
>> +#include "tree.h"
>> +#include "hwint.h"
>> +#include "options.h"
>> +#include "tm.h"
>> +#include "insn-modes.h"
>> +#include "machmode.h"
>> +#include "double-int.h"
>> +#include <gmp.h>
>> +#include "insn-modes.h"
>> +
>>
>> That's a lot of tree and rtl dependencies.  double-int.h avoids these by
>> placing conversion routines in different headers or by only resorting to
>> types in coretypes.h.  Please try to reduce the above to a minimum.
>>
>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>> HOST_BITS_PER_WIDE_INT];
>>
>> are we sure this rounds properly?  Consider a port with max byte mode
>> size 4 on a 64bit host.
>
> I do not believe that this can happen.   The core compiler includes all
> modes up to TI mode, so by default we already up to 128 bits.

And mode bitsizes are always power-of-two?  I suppose so.

>> I still would like to have the ability to provide specializations of
>> wide_int
>> for "small" sizes, thus ideally wide_int would be a template templated
>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>> identical to double_int, thus we should be able to do
>>
>> typedef wide_int<2> double_int;
>
> If you want to go down this path after the patches get in, go for it.    I
> see no use at all for this.
> This was not meant to be a plug in replacement for double int. This goal of
> this patch is to get the compiler to do the constant math the way that the
> target does it.   Any such instantiation is by definition placing some
> predefined limit that some target may not want.

Well, what I don't really like is that we now have two implementations
of functions that perform integer math on two-HWI sized integers.  What
I also don't like too much is that we have two different interfaces to operate
on them!  Can't you see how I come to not liking this?  Especially the
latter ...

>> in double-int.h and replace its implementation with a specialization of
>> wide_int.  Due to a number of divergences (double_int is not a subset
>> of wide_int) that doesn't seem easily possible (one reason is the
>> ShiftOp and related enums you use).  Of course wide_int is not a
>> template either.  For the hypotetical embedded target above we'd
>> end up using wide_int<1>, a even more trivial specialization.
>>
>> I realize again this wide-int is not what your wide-int is (because you
>> add a precision member).  Still factoring out the "common"s of
>> wide-int and double-int into a wide_int_raw <> template should be
>> possible.
>>
>> +class wide_int {
>> +  /* Internal representation.  */
>> +
>> +  /* VAL is set to a size that is capable of computing a full
>> +     multiplication on the largest mode that is represented on the
>> +     target.  The full multiplication is use by tree-vrp.  If
>> +     operations are added that require larger buffers, then VAL needs
>> +     to be changed.  */
>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>> HOST_BITS_PER_WIDE_INT];
>> +  unsigned short len;
>> +  unsigned int bitsize;
>> +  unsigned int precision;
>>
>> The len, bitsize and precision members need documentation.  At least
>> one sounds redundant.
>>
>> + public:
>> +  enum ShiftOp {
>> +    NONE,
>> NONE is never a descriptive name ... I suppose this is for arithmetic vs.
>> logical shifts?
>
> suggest something

Make it an overload instead of passing an extra argument.  Or as I say
make callers apply shift-count truncation separately.

>> +    /* There are two uses for the wide-int shifting functions.  The
>> +       first use is as an emulation of the target hardware.  The
>> +       second use is as service routines for other optimizations.  The
>> +       first case needs to be identified by passing TRUNC as the value
>> +       of ShiftOp so that shift amount is properly handled according to
>> the
>> +       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
>> +       amount is always truncated by the bytesize of the mode of
>> +       THIS.  */
>> +    TRUNC
>>
>> ah, no, it's for SHIFT_COUNT_TRUNCATED.  "mode of THIS"?  Now
>> it's precision I suppose.  That said, handling SHIFT_COUNT_TRUNCATED
>> in wide-int sounds over-engineered, the caller should be responsible
>> of applying SHIFT_COUNT_TRUNCATED when needed.
>
> I am fighting all of the modes out.   i will update this patch with more
> cleanups

Thanks.

>> +  enum SignOp {
>> +    /* Many of the math functions produce different results depending
>> +       on if they are SIGNED or UNSIGNED.  In general, there are two
>> +       different functions, whose names are prefixed with an 'S" and
>> +       or an 'U'.  However, for some math functions there is also a
>> +       routine that does not have the prefix and takes an SignOp
>> +       parameter of SIGNED or UNSIGNED.  */
>> +    SIGNED,
>> +    UNSIGNED
>> +  };
>>
>> double-int and _all_ of the rest of the middle-end uses a 'int uns'
>> parameter
>> for this.  _Please_ follow that.  Otherwise if you communicate between
>> those interfaces you have to to uns ? UNSIGNED : SIGNED and
>> signop == UNSIGNED ? 1 : 0 all over the place.
>
> I really do not want to.   What i discovered is that some places in the
> compiler do and some places do not and some places take the reverse
> convention  MNEMONIC is better than NUMERIC.

I don't think that you scheme is an improvement given that GCC has a
mix of both.  I also fail to remember a place where it is not unsigned == 1,
signed == 0 (which you btw reverse ... SIGNED == 0, UNSIGNED ==1,
so even ugly casting doesn't allow moderating between the two schemes).

>>
>> +  static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize,
>> +                            unsigned int precision);
>> +  static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize,
>> +                            unsigned int precision, bool *overflow);
>>
>> I suppose , bool *overflow = NULL would do as well?  What's the
>> distinction between bitsize and precision (I suppose, see the above
>> question)?  I suppose precision <= bitsize and bits above precision
>> are sign/zero extended (and the rest of the val[] array contains undefined
>> content?)?  But we also have 'len', which then matches bitsize (well
>> it may be larger).  So IMHO either bitsize or len is redundant.  At least
>> the tree level nowhere considers partial integer modes special this way
>> (only the precision is ever taken into account, but we always
>> sign-/zero-extend
>> to the whole double-int - thus 'len' in wide-int terms).
>
> Some operations, mostly shifting, needs  both the bitsize and precision.
> In the early days of the compiler, people pretty much ignored the precision
> and most of the compiler math was done using the bitsize.   This made it
> very painful for the people who supported ports that had odd sized modes.
> Bernd has been cleaning this up at the rtl level and the first 5 patches
> move that forward.   But you really do need both.

I fail to understand.  How do you require anything else than precision for
shifting?  Do you say that shifting a PSImode 24-bit precision integer right
with a logical shift will pull in sign-bits that happen to be 'extended' into
the upper 8 bits?  Richard, can you clarify this please?  I still see
len == bitsize and thus a redundancy.

>> +  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type);
>> +  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type,
>> +                                  bool *overflow);
>>
>> Are you needing this overload or are you adding it for "completeness"?
>> Because this interface is wrong(TM), and whoever calls it has at least
>> cleanup opportunities ... from_tree or from_rtx makes sense.
>
> the functions are actually quite different.    in general overflow checking
> at least doubles the cost of implementation and sometimes it is much
> greater.   Having them be separate cleans up the implementation.

Still in the above you take the actual value from op0, a HOST_WIDE_INT
(with what precison / bitsize?), the wide_int will have precision / bitsize
from the tree type argument (will op0 be truncated / extended here?  How
is *overflow computed?).

Btw, if you have an overload like this please make 'overflow' a reference,
it doesn't make sense to pass NULL here (just use the other overload).

>
>
>>
>> Also in which cases do you need "overflow"?  a HWI always fits in
>> a wide-int!  All trees and rtxen do, too.  You seem to merge two
>> operations here, conversion to wide-int and truncation / extension.
>> That doesn't look like a clean interface to me.
>
> This is the big difference between double_int and wide_int:    I do not care
> if it fits in the underlying representation, i care if it fits in the
> precision of the type.   If the type is for a char and the value is 100000,
> overflow is set.   In general setting overflow in the wide-int interface
> means something very different from double-int interface.    A large number
> of places that check for overflow with double in do not need to check it for
> wide int.

Then in the above interface you really want to ask hwi_fits_type_p instead
of globbing this into the construction of a wide-int.  (This whole interface
is really a mess - sorry)

If overflow setting for wide-int means somehting very different from double-int
then it shouldn't be called overflow or it should at least be documented!
So - what does it actually mean?  Double-ints implicitely have precision
of 2*HWI so overflow is set whenever the operation overflows that precision.
It doesn't make sense to ask if a HWI fits in a double-int for example.

>> +  static wide_int from_double_int (enum machine_mode, double_int);
>>
>> the choice of passing a mode seems arbitrary (the natural interface
>> would be nothing - precision is 2 * HWI).  Passing it as first parameter
>> is even more strange to me ;)
>
> the first part of the question is answered above.   the second part of the
> question was fixed on my private tree a few days ago and will get pushed
> out.

Thanks.

>> +  static wide_int from_tree (const_tree);
>> +  static wide_int from_rtx (const_rtx, enum machine_mode);
>>
>> +  HOST_WIDE_INT to_shwi (unsigned int prec) const;
>>
>> See above - merges two basic operations.  You should write
>>
>>   w.sext (prec).to_shwi ()
>>
>> instead (I _suppose_ it should sign-extend, should it? ;)).  Btw, why
>> don't we need to always specify bitsize together with precision in all
>> the places?  (not that I am arguing for it, I'm arguing for the
>> removal of bitsize)
>
> because the bitsize and precision are part of the representation of the
> value.    You only have to specify them on the way into wide-int or if you
> need to change them (this is rare but it does happen).

My objection to to_shwi still stands.  to_shwi should be

 HOST_WIDE_INT to_shwi () const;

and it could gcc_assert () that the wide-int fits in a shwi (you should be
able to see a pattern in my complaints ...)

>> +  static wide_int max_value (unsigned int bitsize, unsigned int prec,
>> SignOp sgn);
>>
>> now that I am seeing this - is there any restriction on how the precision
>> of a partial integer mode may differ from its bitsize?  Can we have
>> POImode with 1 bit precision?  I suppose the solution for all this is
>> that when converting a wide-int to a RTX with a mode then we need to
>> zero-/sign-extend to the modes bitsize (and wide-int only cares about
>> precision).  Eventually a set_len can adjust the amount of BITS_PER_UNITs
>> we fill with meaningful values if needed.  Otherwise len == precision
>> / BITS_PER_UNIT (rounded to HWI for obvious practical reasons).
>
> the precision must be less than or equal to the bitsize.   That is the only
> restriction.
> I do not know if you can have poi1?    Every case that i have seen, the
> partial int is a partial of the next largest power of 2 mode. But there is
> nothing in wide-int that cares about this.
>
>
>>
>> +  inline static wide_int minus_one (unsigned int bitsize, unsigned int
>> prec);
>> +  inline static wide_int minus_one (const_tree type);
>> +  inline static wide_int minus_one (enum machine_mode mode);
>> +  inline static wide_int zero (unsigned int bitsize, unsigned int prec);
>> +  inline static wide_int zero (const_tree type);
>> +  inline static wide_int zero (enum machine_mode mode);
>> +  inline static wide_int one (unsigned int bitsize, unsigned int prec);
>> +  inline static wide_int one (const_tree type);
>> +  inline static wide_int one (enum machine_mode mode);
>> +  inline static wide_int two (unsigned int bitsize, unsigned int prec);
>> +  inline static wide_int two (const_tree type);
>> +  inline static wide_int two (enum machine_mode mode);
>> +  inline static wide_int ten (unsigned int bitsize, unsigned int prec);
>> +  inline static wide_int ten (const_tree type);
>> +  inline static wide_int ten (enum machine_mode mode);
>>
>> wheeee .... ;)
>
> yes, and they are all used.
>
>> What's wrong with from_uhwi (10, ...)?  double-int has the above for
>> compatibility reasons only.  And why should I care about type/mode/size
>> for something as simple as '1'?
>
> the 10 is an interesting case.   at least in my patches it is not used, but
> i had put it in because i started from double-int and it has it.   However,
> i believe in fat api's if something gets used a lot, then it should be part
> of the api.    all of them except for 10 are used a lot.
>
> I will point out than in my original patch, these were just macros that
> expanded into from_uhwi, but richi wanted them to be real functions.

Yeah, but now with all the fancy overloads (but see my other suggestion below).

>
>
>
>> +  inline unsigned short get_len () const;
>> +  inline unsigned int get_bitsize () const;
>> +  inline unsigned int get_precision () const;
>> +  inline unsigned int get_full_len () const;
>>
>> not sure which air you are pulling full_len from ;)
>
> when you need it, you need it.   the dwarf writer really needs it, because
> it wants to see all of the words on a multiword value, not just the ones
> that "need" to be represented so that it is easy to read.
>
> I have a big comment on when not to use this in my tree.


+  /* VRP appears to be badly broken and this is a very ugly fix.  */
+  if (i >= 0)
+    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);

Err??  You mean you are getting array-bound warnings or what?


>> +  wide_int force_to_size (unsigned int bitsize,
>> +                         unsigned int precision) const;
>>
>> or rather 'trunc'?  Seems to be truncation and set_len combined?
>
> why do you think it is only shortening it?

Because it does not say whether you sign- or zero-extend:

+/* Copy THIS replacing the mode with MODE.  */

Fix comment.

+wide_int
+wide_int::force_to_size (unsigned int bs, unsigned int prec) const
+{
+  wide_int result;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (prec);
+  int i;
+
+  result.bitsize = bs;
+  result.precision = prec;
+  result.len = blocks_needed < len ? blocks_needed : len;
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+
+  if (small_prec & (blocks_needed == len))

what?  small_prec seems to tell you whether precision is a
multiple of a HWI, now you only look at bit 1 (so it's equal
to precision & (blocks_needed == len).

+    result.val[blocks_needed-1]
+      = sext_hwi (result.val[blocks_needed-1], small_prec);

But I really think you want sth else...  maybe &&?  You also unconditionally
sign-extend, so the function name should somehow reflect this.

+  return result;
+}


>
>>
>> I wonder if for the various ways to specify precision/len there is a nice
>> C++
>> way of moving this detail out of wide-int.  I can think only of one:
>>
>> struct WIntSpec {
>>    WIntSpec (unsigned int len, unsigned int precision);
>>    WIntSpec (const_tree);
>>    WIntSpec (enum machine_mode);
>>    unsigned int len;
>>    unsigned int precision;
>> };
>>
>> and then (sorry to pick one of the less useful functions):
>>
>>    inline static wide_int zero (WIntSpec)
>
> It depends on what you have available in your hands when you need to call a
> function.   At the rtl level we almost never have tree types, but we have
> modes.    At the tree level, you almost never have modes.    In general the
> convenience functions take anything and just extract the prec and bitsize
> for you.    But there are several places that need to specify the prec and
> bitsize and so these are now the base primitives.

You always have prec and bitsize.  GET_MODE_PRECISION and
GET_MODE_BITSIZE, TYPE_PRECISION and TYPE_SIZE tell you this.
The other overloads are for convenience only.  You didn't respond to
the idea of making the interface less cluttered by using some abstraction.

>> which you should be able to call like
>>
>>    wide_int::zero (SImode)
>>    wide_int::zero (integer_type_node)
>>
>> and (ugly)
>>
>>    wide_int::zero (WIntSpec (32, 32))
>>
>> with C++0x wide_int::zero ({32, 32}) should be possible?  Or we keep
>> the precision overload.  At least providing the WIntSpec abstraction
>> allows custom ways of specifying required bits to not pollute wide-int
>> itself too much.  Lawrence?
>>
>> +  /* Printing functions.  */
>> +
>> +  void print_dec (char *buf, SignOp sgn) const;
>> +  void print_dec (FILE *file, SignOp sgn) const;
>> +  void print_decs (char *buf) const;
>> +  void print_decs (FILE *file) const;
>> +  void print_decu (char *buf) const;
>> +  void print_decu (FILE *file) const;
>> +  void print_hex (char *buf) const;
>> +  void print_hex (FILE *file) const;
>>
>> consider moving them to standalone functions, out of wide-int.h
>
> I do not see much reason to do this.    They use the internals of wide-int
> and moving them somewhere else is just exposing the internals for no real
> reason.

All internals are exposed already.

>>
>> +  inline bool minus_one_p () const;
>> +  inline bool zero_p () const;
>> +  inline bool one_p () const;
>> +  inline bool neg_p () const;
>>
>> what's wrong with w == -1, w == 0, w == 1, etc.?
>
> I would love to do this and you seem to be somewhat knowledgeable of c++.
> But i cannot for the life of me figure out how to do it.
>
> say i have a TImode number, which must be represented in 4 ints on a 32 bit
> host (the same issue happens on 64 bit hosts, but the examples are simpler
> on 32 bit hosts) and i compare it to -1.    The value that i am going to see
> as the argument of the function is going have the value 0xffffffff.
> but the value that i have internally is 128 bits.   do i take this and 0 or
> sign extend it?   in particular if someone wants to compare a number to
> 0xdeadbeef  i have no idea what to do.   I tried defining two different
> functions, one that took a signed and one that took and unsigned number but
> then i wanted a cast in front of all the positive numbers.
>
> If there is a way to do this, then i will do it, but it is going to have to
> work properly for things larger than a HOST_WIDE_INT.
>
> I know that double-int does some of this and it does not carry around a
> notion of signedness either.   is this just code that has not been fully
> tested or is there a trick in c++ that i am missing?

Not sure, but at least minus_one_p, zero_p and one_p can be implemented
with a signed HWI overload of operator==

But I suppose leaving things as-is is fine as well.

>> +  bool only_sign_bit_p (unsigned int prec) const;
>> +  bool only_sign_bit_p () const;
>>
>> what's that?  Some of the less obvious functions should be documented
>> in the header I think.  Smells of combining two things again here.
>> Either wide-int has an intrinsic precision or it has not ... (like
>> double-int).
>
>
> Again, i have put in things that are useful, it is all driven from what the
> clients need.    This is done all over the back end.

What's the current function that is called?

>>
>> +  bool fits_u_p (unsigned int prec) const;
>> +  bool fits_s_p (unsigned int prec) const;
>>
>> See above.
>>
>> +  /* Extension  */
>> +
>> +  inline wide_int ext (unsigned int offset, SignOp sgn) const;
>> +  wide_int sext (unsigned int offset) const;
>> +  wide_int sext (enum machine_mode mode) const;
>> +  wide_int zext (unsigned int offset) const;
>> +  wide_int zext (enum machine_mode mode) const;
>>
>> 'offset'?  I suppose that's 'precision'.  Does that alter the
>> precision of *this?
>> I think it should (and thus there should be no set_precision function).
>> If it doesn't alter precision the functions don't make much sense to me.
>
> The ones that alter the precision take a precision and bitsize, the ones
> that just want do the extension from some place and end up with a bit
> pattern that looks a certain way take the offset.

Different semantics for a function overload is ... ugly.

>
>> +  wide_int set_bit (unsigned int bitpos) const;
>>
>> this kind of interface is strange.  You call it like w.set_bit (1) but it
>> doesn't actually set bit 1 in w but it constructs a new wide_int and
>> returns that.  So I suppose it should be
>>
>>    wide_int with_bit_set (unsigned int bitpos) const;
>
> the interface is pure.    if you want me to change the name, that is fine.
>
>>
>> or similar.  Or simply have a mutating set_bit.  Or leave it out entierly,
>> we cannot have many uses of this kind of weird interface.
>>
>> similar comments for the rest.
>>
>> .... rest skipped ...
>>
>> +                                   / HOST_BITS_PER_WIDE_INT + 32));
>> +  char *dump (char* buf) const;
>> + private:
>> +
>> +  /* Private utility routines.  */
>> +  wide_int decompress (unsigned int target, unsigned int bitsize,
>> +                      unsigned int precision) const;
>> +  static wide_int add_overflow (const wide_int *op0, const wide_int *op1,
>> +                               wide_int::SignOp sgn, bool *overflow);
>> +  static wide_int sub_overflow (const wide_int *op0, const wide_int *op1,
>> +                               wide_int::SignOp sgn, bool *overflow);
>> +};
>>
>>
>> IMHO way too many functions for a well tested initial implementation.
>> There are a lot of things that seem operation compositions.  Is your
>> concern efficiency here?  That would be bad as that means wide_ints
>> are too heavy weight.
>
> There are two sides of ease of use, you can force people to write out
> everything using a few primitives or you give them a rich interface.    I
> come from the rich interface school.
>
> If i was just going out and selling a new interface, something clean and
> small would be easier to sell.   However, that is not what i am doing.    I
> have converted substantially the entire back end to this and in the next few
> days i will submit patches that do the tree level.   So i am a big user and
> a rich api makes that conversion much easier.

Maybe for you, but not for people that come looking for a way to do
something with that interface.  They see a galore of functions with
similar names and weird arguments.  They try to figure out which to pick
and get confused.  They end up resorting to the _implementation_ :(

The interface is, frankly, a mess.  And I don't agree that it is a pre-existing
interface.  The wide-int class should have a clean and small interface.

You can write the rich interface as standalone functions, the clean and
small interface should provide all building blocks you need.

> Remember that these patches are not syntactic changes like the conversion of
> double-int to use c++ interfaces.    I am actually converting most of the
> code that only does transformations if the value fits in some fixed number
> of HWIs to work at the targets precision.   My motivation is that GCC does
> not actually work correctly with larger types.   I will do what it takes to
> get these patches in an acceptable form to the api police but my motivations
> is that the compiler is now neither correct nor robust with 128 bit types
> and above.

Well, you may gain that things work with 128 bit and above types, but
at the same time GCC will be a more confusing place to work with.

One general implementation detail comment:

+class wide_int {
+  /* Internal representation.  */
+
+  /* VAL is set to a size that is capable of computing a full
+     multiplication on the largest mode that is represented on the
+     target.  The full multiplication is use by tree-vrp.  If
+     operations are added that require larger buffers, then VAL needs
+     to be changed.  */
+  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  unsigned short len;
+  unsigned int bitsize;
+  unsigned int precision;

put VAL last so one can allocate less storage, thus it should be a trailing
array.  Make all of wide-int have non-mutating 'len' (that's required to
make variable storage size for VAL viable).  Thus,

    const unsigned int len;
    unsigned int bitsize;
    unsigned int precision;
    HOST_WIDE_INT val[1 /* len */];

that is, how much of the wide-int implementation is mutating?  (I'd
even say bitsize and precision should be 'const').

Then of couse I'd factor out the bitsize / precision notion into a
wrapper to be able to do the double-int sharing I am after...

Richard.

> kenny
>
>
>> Can you use gcov to see which functions have (how much) coverage?
>>
>> Thanks,
>> Richard.
>>
>>
>>
>>> kenny
>>>
>>>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-24 10:10                                               ` Richard Biener
@ 2012-10-24 17:30                                                 ` Mike Stump
  2012-10-25 10:55                                                   ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Mike Stump @ 2012-10-24 17:30 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kenneth Zadeck, gcc-patches, rdsandiford, Lawrence Crowl

On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guenther@gmail.com> wrote:
> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> 
>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>> 
>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>> HOST_BITS_PER_WIDE_INT];
>>> 
>>> are we sure this rounds properly?  Consider a port with max byte mode
>>> size 4 on a 64bit host.
>> 
>> I do not believe that this can happen.   The core compiler includes all
>> modes up to TI mode, so by default we already up to 128 bits.
> 
> And mode bitsizes are always power-of-two?  I suppose so.

Actually, no, they are not.  Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size.  Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /  HOST_BITS_PER_WIDE_INT should do it.

>>> I still would like to have the ability to provide specializations of
>>> wide_int
>>> for "small" sizes, thus ideally wide_int would be a template templated
>>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>>> identical to double_int, thus we should be able to do
>>> 
>>> typedef wide_int<2> double_int;
>> 
>> If you want to go down this path after the patches get in, go for it.    I
>> see no use at all for this.
>> This was not meant to be a plug in replacement for double int. This goal of
>> this patch is to get the compiler to do the constant math the way that the
>> target does it.   Any such instantiation is by definition placing some
>> predefined limit that some target may not want.
> 
> Well, what I don't really like is that we now have two implementations
> of functions that perform integer math on two-HWI sized integers.  What
> I also don't like too much is that we have two different interfaces to operate
> on them!  Can't you see how I come to not liking this?  Especially the
> latter …

double_int is logically dead.  Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler.  All the necessary semantics and code of double-int _has_ been refactored into wide-int already.  Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed.  The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-24 17:30                                                 ` Mike Stump
@ 2012-10-25 10:55                                                   ` Richard Biener
  2012-10-25 10:59                                                     ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2012-10-25 10:55 UTC (permalink / raw)
  To: Mike Stump; +Cc: Kenneth Zadeck, gcc-patches, rdsandiford, Lawrence Crowl

On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump <mikestump@comcast.net> wrote:
> On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guenther@gmail.com> wrote:
>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>> <zadeck@naturalbridge.com> wrote:
>>>
>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>
>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>> HOST_BITS_PER_WIDE_INT];
>>>>
>>>> are we sure this rounds properly?  Consider a port with max byte mode
>>>> size 4 on a 64bit host.
>>>
>>> I do not believe that this can happen.   The core compiler includes all
>>> modes up to TI mode, so by default we already up to 128 bits.
>>
>> And mode bitsizes are always power-of-two?  I suppose so.
>
> Actually, no, they are not.  Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size.  Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /  HOST_BITS_PER_WIDE_INT should do it.
>
>>>> I still would like to have the ability to provide specializations of
>>>> wide_int
>>>> for "small" sizes, thus ideally wide_int would be a template templated
>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>>>> identical to double_int, thus we should be able to do
>>>>
>>>> typedef wide_int<2> double_int;
>>>
>>> If you want to go down this path after the patches get in, go for it.    I
>>> see no use at all for this.
>>> This was not meant to be a plug in replacement for double int. This goal of
>>> this patch is to get the compiler to do the constant math the way that the
>>> target does it.   Any such instantiation is by definition placing some
>>> predefined limit that some target may not want.
>>
>> Well, what I don't really like is that we now have two implementations
>> of functions that perform integer math on two-HWI sized integers.  What
>> I also don't like too much is that we have two different interfaces to operate
>> on them!  Can't you see how I come to not liking this?  Especially the
>> latter …
>
> double_int is logically dead.  Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler.  All the necessary semantics and code of double-int _has_ been refactored into wide-int already.  Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed.  The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that.

double_int, compared to wide_int, is fast and lean.  I doubt we will
get rid of it - you
will make compile-time math a _lot_ slower.  Just profile when you for example
change get_inner_reference to use wide_ints.

To be able to remove double_int in favor of wide_int requires _at least_
templating wide_int on 'len' and providing specializations for 1 and 2.

It might be a non-issue for math that operates on trees or RTXen due to
the allocation overhead we pay, but in recent years we transitioned important
paths away from using tree math to using double_ints _for speed reasons_.

Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-25 10:55                                                   ` Richard Biener
@ 2012-10-25 10:59                                                     ` Kenneth Zadeck
  2012-10-25 12:12                                                       ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-25 10:59 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, rdsandiford, Lawrence Crowl


On 10/25/2012 06:42 AM, Richard Biener wrote:
> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump <mikestump@comcast.net> wrote:
>> On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guenther@gmail.com> wrote:
>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>> <zadeck@naturalbridge.com> wrote:
>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>
>>>>> are we sure this rounds properly?  Consider a port with max byte mode
>>>>> size 4 on a 64bit host.
>>>> I do not believe that this can happen.   The core compiler includes all
>>>> modes up to TI mode, so by default we already up to 128 bits.
>>> And mode bitsizes are always power-of-two?  I suppose so.
>> Actually, no, they are not.  Partial int modes can have bit sizes that are not power of two, and, if there isn't an int mode that is bigger, we'd want to round up the partial int bit size.  Something like ((2 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /  HOST_BITS_PER_WIDE_INT should do it.
>>
>>>>> I still would like to have the ability to provide specializations of
>>>>> wide_int
>>>>> for "small" sizes, thus ideally wide_int would be a template templated
>>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>>>>> identical to double_int, thus we should be able to do
>>>>>
>>>>> typedef wide_int<2> double_int;
>>>> If you want to go down this path after the patches get in, go for it.    I
>>>> see no use at all for this.
>>>> This was not meant to be a plug in replacement for double int. This goal of
>>>> this patch is to get the compiler to do the constant math the way that the
>>>> target does it.   Any such instantiation is by definition placing some
>>>> predefined limit that some target may not want.
>>> Well, what I don't really like is that we now have two implementations
>>> of functions that perform integer math on two-HWI sized integers.  What
>>> I also don't like too much is that we have two different interfaces to operate
>>> on them!  Can't you see how I come to not liking this?  Especially the
>>> latter Â…
>> double_int is logically dead.  Reactoring wide-int and double-int is a waste of time, as the time is better spent removing double-int from the compiler.  All the necessary semantics and code of double-int _has_ been refactored into wide-int already.  Changing wide-int in any way to vend anything to double-int is wrong, as once double-int is removed, then all the api changes to make double-int share from wide-int is wasted and must then be removed.  The path forward is the complete removal of double-int; it is wrong, has been wrong and always will be wrong, nothing can change that.
> double_int, compared to wide_int, is fast and lean.  I doubt we will
> get rid of it - you
> will make compile-time math a _lot_ slower.  Just profile when you for example
> change get_inner_reference to use wide_ints.
>
> To be able to remove double_int in favor of wide_int requires _at least_
> templating wide_int on 'len' and providing specializations for 1 and 2.
>
> It might be a non-issue for math that operates on trees or RTXen due to
> the allocation overhead we pay, but in recent years we transitioned important
> paths away from using tree math to using double_ints _for speed reasons_.
>
> Richard.
i do not know why you believe this about the speed.     double int 
always does synthetic math since you do everything at 128 bit precision.

the thing about wide int, is that since it does math to the precision's 
size, it almost never does uses synthetic operations since the sizes for 
almost every instance can be done using the native math on the 
machine.   almost every call has a check to see if the operation can be 
done natively.    I seriously doubt that you are going to do TI mode 
math much faster than i do it and if you do who cares.

the number of calls does not effect the performance in any negative way 
and it fact is more efficient since common things that require more than 
one operation in double in are typically done in a single operation.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-25 10:59                                                     ` Kenneth Zadeck
@ 2012-10-25 12:12                                                       ` Richard Biener
  2012-10-31 11:01                                                         ` Richard Sandiford
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2012-10-25 12:12 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, rdsandiford, Lawrence Crowl

On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
>
> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>
>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump <mikestump@comcast.net> wrote:
>>>
>>> On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guenther@gmail.com>
>>> wrote:
>>>>
>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>> <zadeck@naturalbridge.com> wrote:
>>>>>
>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>
>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>
>>>>>> are we sure this rounds properly?  Consider a port with max byte mode
>>>>>> size 4 on a 64bit host.
>>>>>
>>>>> I do not believe that this can happen.   The core compiler includes all
>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>
>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>
>>> Actually, no, they are not.  Partial int modes can have bit sizes that
>>> are not power of two, and, if there isn't an int mode that is bigger, we'd
>>> want to round up the partial int bit size.  Something like ((2 *
>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>> HOST_BITS_PER_WIDE_INT should do it.
>>>
>>>>>> I still would like to have the ability to provide specializations of
>>>>>> wide_int
>>>>>> for "small" sizes, thus ideally wide_int would be a template templated
>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>>>>>> identical to double_int, thus we should be able to do
>>>>>>
>>>>>> typedef wide_int<2> double_int;
>>>>>
>>>>> If you want to go down this path after the patches get in, go for it.
>>>>> I
>>>>> see no use at all for this.
>>>>> This was not meant to be a plug in replacement for double int. This
>>>>> goal of
>>>>> this patch is to get the compiler to do the constant math the way that
>>>>> the
>>>>> target does it.   Any such instantiation is by definition placing some
>>>>> predefined limit that some target may not want.
>>>>
>>>> Well, what I don't really like is that we now have two implementations
>>>> of functions that perform integer math on two-HWI sized integers.  What
>>>> I also don't like too much is that we have two different interfaces to
>>>> operate
>>>> on them!  Can't you see how I come to not liking this?  Especially the
>>>> latter …
>>>
>>> double_int is logically dead.  Reactoring wide-int and double-int is a
>>> waste of time, as the time is better spent removing double-int from the
>>> compiler.  All the necessary semantics and code of double-int _has_ been
>>> refactored into wide-int already.  Changing wide-int in any way to vend
>>> anything to double-int is wrong, as once double-int is removed, then all the
>>> api changes to make double-int share from wide-int is wasted and must then
>>> be removed.  The path forward is the complete removal of double-int; it is
>>> wrong, has been wrong and always will be wrong, nothing can change that.
>>
>> double_int, compared to wide_int, is fast and lean.  I doubt we will
>> get rid of it - you
>> will make compile-time math a _lot_ slower.  Just profile when you for
>> example
>> change get_inner_reference to use wide_ints.
>>
>> To be able to remove double_int in favor of wide_int requires _at least_
>> templating wide_int on 'len' and providing specializations for 1 and 2.
>>
>> It might be a non-issue for math that operates on trees or RTXen due to
>> the allocation overhead we pay, but in recent years we transitioned
>> important
>> paths away from using tree math to using double_ints _for speed reasons_.
>>
>> Richard.
>
> i do not know why you believe this about the speed.     double int always
> does synthetic math since you do everything at 128 bit precision.
>
> the thing about wide int, is that since it does math to the precision's
> size, it almost never does uses synthetic operations since the sizes for
> almost every instance can be done using the native math on the machine.
> almost every call has a check to see if the operation can be done natively.
> I seriously doubt that you are going to do TI mode math much faster than i
> do it and if you do who cares.
>
> the number of calls does not effect the performance in any negative way and
> it fact is more efficient since common things that require more than one
> operation in double in are typically done in a single operation.

Simple double-int operations like

inline double_int
double_int::and_not (double_int b) const
{
  double_int result;
  result.low = low & ~b.low;
  result.high = high & ~b.high;
  return result;
}

are always going to be faster than conditionally executing only one operation
(but inside an offline function).

Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-25 12:12                                                       ` Richard Biener
@ 2012-10-31 11:01                                                         ` Richard Sandiford
  2012-10-31 12:01                                                           ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2012-10-31 11:01 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl

Richard Biener <richard.guenther@gmail.com> writes:
> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>>
>> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>>
>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump <mikestump@comcast.net> wrote:
>>>>
>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guenther@gmail.com>
>>>> wrote:
>>>>>
>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>
>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>>
>>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>>
>>>>>>> are we sure this rounds properly?  Consider a port with max byte mode
>>>>>>> size 4 on a 64bit host.
>>>>>>
>>>>>> I do not believe that this can happen.   The core compiler includes all
>>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>>
>>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>>
>>>> Actually, no, they are not.  Partial int modes can have bit sizes that
>>>> are not power of two, and, if there isn't an int mode that is bigger, we'd
>>>> want to round up the partial int bit size.  Something like ((2 *
>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>>> HOST_BITS_PER_WIDE_INT should do it.
>>>>
>>>>>>> I still would like to have the ability to provide specializations of
>>>>>>> wide_int
>>>>>>> for "small" sizes, thus ideally wide_int would be a template templated
>>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>>>>>>> identical to double_int, thus we should be able to do
>>>>>>>
>>>>>>> typedef wide_int<2> double_int;
>>>>>>
>>>>>> If you want to go down this path after the patches get in, go for it.
>>>>>> I
>>>>>> see no use at all for this.
>>>>>> This was not meant to be a plug in replacement for double int. This
>>>>>> goal of
>>>>>> this patch is to get the compiler to do the constant math the way that
>>>>>> the
>>>>>> target does it.   Any such instantiation is by definition placing some
>>>>>> predefined limit that some target may not want.
>>>>>
>>>>> Well, what I don't really like is that we now have two implementations
>>>>> of functions that perform integer math on two-HWI sized integers.  What
>>>>> I also don't like too much is that we have two different interfaces to
>>>>> operate
>>>>> on them!  Can't you see how I come to not liking this?  Especially the
>>>>> latter …
>>>>
>>>> double_int is logically dead.  Reactoring wide-int and double-int is a
>>>> waste of time, as the time is better spent removing double-int from the
>>>> compiler.  All the necessary semantics and code of double-int _has_ been
>>>> refactored into wide-int already.  Changing wide-int in any way to vend
>>>> anything to double-int is wrong, as once double-int is removed, then all the
>>>> api changes to make double-int share from wide-int is wasted and must then
>>>> be removed.  The path forward is the complete removal of double-int; it is
>>>> wrong, has been wrong and always will be wrong, nothing can change that.
>>>
>>> double_int, compared to wide_int, is fast and lean.  I doubt we will
>>> get rid of it - you
>>> will make compile-time math a _lot_ slower.  Just profile when you for
>>> example
>>> change get_inner_reference to use wide_ints.
>>>
>>> To be able to remove double_int in favor of wide_int requires _at least_
>>> templating wide_int on 'len' and providing specializations for 1 and 2.
>>>
>>> It might be a non-issue for math that operates on trees or RTXen due to
>>> the allocation overhead we pay, but in recent years we transitioned
>>> important
>>> paths away from using tree math to using double_ints _for speed reasons_.
>>>
>>> Richard.
>>
>> i do not know why you believe this about the speed.     double int always
>> does synthetic math since you do everything at 128 bit precision.
>>
>> the thing about wide int, is that since it does math to the precision's
>> size, it almost never does uses synthetic operations since the sizes for
>> almost every instance can be done using the native math on the machine.
>> almost every call has a check to see if the operation can be done natively.
>> I seriously doubt that you are going to do TI mode math much faster than i
>> do it and if you do who cares.
>>
>> the number of calls does not effect the performance in any negative way and
>> it fact is more efficient since common things that require more than one
>> operation in double in are typically done in a single operation.
>
> Simple double-int operations like
>
> inline double_int
> double_int::and_not (double_int b) const
> {
>   double_int result;
>   result.low = low & ~b.low;
>   result.high = high & ~b.high;
>   return result;
> }
>
> are always going to be faster than conditionally executing only one operation
> (but inside an offline function).

OK, this is really in reply to the 4.8 thing, but it felt more
appropriate here.

It's interesting that you gave this example, since before you were
complaining about too many fused ops.  Clearly this one could be
removed in favour of separate and() and not() operations, but why
not provide a fused one if there are clients who'll make use of it?
I think Kenny's API is just taking that to its logical conclusion.
There doesn't seem to be anything sacrosanct about the current choice
of what's fused and what isn't.

The speed problem we had using trees for internal arithmetic isn't
IMO a good argument for keeping double_int in preference to wide_int.
Allocating and constructing tree objects to hold temporary values,
storing an integer representation in it, then calling tree arithmetic
routines that pull out the integer representation again and create a
tree to hold the result, is going to be much slower than using either
double_int or wide_int.  I'd be very surprised if we notice any
measurable difference between double_int and wide_int here.

I still see no reason to keep double_int around.  The width of a host
wide integer really shouldn't have any significance.

Your main complaint seems to be that the wide_int API is different
from the double_int one, but we can't literally use the same API, since
double_int has an implicit precision and bitsize, and wide_int doesn't.
Having a precision that is separate from the underlying representation
is IMO the most important feature of wide_int, so:

   template wide_int<2> double_int;

is never going to be a drop-in, API-compatible replacement for double_int.

FWIW, I like the idea about having a class that wraps up the mode,
tree, and (precision, bitsize) choice.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 11:01                                                         ` Richard Sandiford
@ 2012-10-31 12:01                                                           ` Richard Biener
  2012-10-31 12:12                                                             ` Richard Sandiford
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2012-10-31 12:01 UTC (permalink / raw)
  To: Richard Biener, Kenneth Zadeck, Mike Stump, gcc-patches,
	Lawrence Crowl, rdsandiford

On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
>> <zadeck@naturalbridge.com> wrote:
>>>
>>> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>>>
>>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump <mikestump@comcast.net> wrote:
>>>>>
>>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guenther@gmail.com>
>>>>> wrote:
>>>>>>
>>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>
>>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>>>
>>>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>>>
>>>>>>>> are we sure this rounds properly?  Consider a port with max byte mode
>>>>>>>> size 4 on a 64bit host.
>>>>>>>
>>>>>>> I do not believe that this can happen.   The core compiler includes all
>>>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>>>
>>>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>>>
>>>>> Actually, no, they are not.  Partial int modes can have bit sizes that
>>>>> are not power of two, and, if there isn't an int mode that is bigger, we'd
>>>>> want to round up the partial int bit size.  Something like ((2 *
>>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>>>> HOST_BITS_PER_WIDE_INT should do it.
>>>>>
>>>>>>>> I still would like to have the ability to provide specializations of
>>>>>>>> wide_int
>>>>>>>> for "small" sizes, thus ideally wide_int would be a template templated
>>>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>>>>>>>> identical to double_int, thus we should be able to do
>>>>>>>>
>>>>>>>> typedef wide_int<2> double_int;
>>>>>>>
>>>>>>> If you want to go down this path after the patches get in, go for it.
>>>>>>> I
>>>>>>> see no use at all for this.
>>>>>>> This was not meant to be a plug in replacement for double int. This
>>>>>>> goal of
>>>>>>> this patch is to get the compiler to do the constant math the way that
>>>>>>> the
>>>>>>> target does it.   Any such instantiation is by definition placing some
>>>>>>> predefined limit that some target may not want.
>>>>>>
>>>>>> Well, what I don't really like is that we now have two implementations
>>>>>> of functions that perform integer math on two-HWI sized integers.  What
>>>>>> I also don't like too much is that we have two different interfaces to
>>>>>> operate
>>>>>> on them!  Can't you see how I come to not liking this?  Especially the
>>>>>> latter …
>>>>>
>>>>> double_int is logically dead.  Reactoring wide-int and double-int is a
>>>>> waste of time, as the time is better spent removing double-int from the
>>>>> compiler.  All the necessary semantics and code of double-int _has_ been
>>>>> refactored into wide-int already.  Changing wide-int in any way to vend
>>>>> anything to double-int is wrong, as once double-int is removed, then all the
>>>>> api changes to make double-int share from wide-int is wasted and must then
>>>>> be removed.  The path forward is the complete removal of double-int; it is
>>>>> wrong, has been wrong and always will be wrong, nothing can change that.
>>>>
>>>> double_int, compared to wide_int, is fast and lean.  I doubt we will
>>>> get rid of it - you
>>>> will make compile-time math a _lot_ slower.  Just profile when you for
>>>> example
>>>> change get_inner_reference to use wide_ints.
>>>>
>>>> To be able to remove double_int in favor of wide_int requires _at least_
>>>> templating wide_int on 'len' and providing specializations for 1 and 2.
>>>>
>>>> It might be a non-issue for math that operates on trees or RTXen due to
>>>> the allocation overhead we pay, but in recent years we transitioned
>>>> important
>>>> paths away from using tree math to using double_ints _for speed reasons_.
>>>>
>>>> Richard.
>>>
>>> i do not know why you believe this about the speed.     double int always
>>> does synthetic math since you do everything at 128 bit precision.
>>>
>>> the thing about wide int, is that since it does math to the precision's
>>> size, it almost never does uses synthetic operations since the sizes for
>>> almost every instance can be done using the native math on the machine.
>>> almost every call has a check to see if the operation can be done natively.
>>> I seriously doubt that you are going to do TI mode math much faster than i
>>> do it and if you do who cares.
>>>
>>> the number of calls does not effect the performance in any negative way and
>>> it fact is more efficient since common things that require more than one
>>> operation in double in are typically done in a single operation.
>>
>> Simple double-int operations like
>>
>> inline double_int
>> double_int::and_not (double_int b) const
>> {
>>   double_int result;
>>   result.low = low & ~b.low;
>>   result.high = high & ~b.high;
>>   return result;
>> }
>>
>> are always going to be faster than conditionally executing only one operation
>> (but inside an offline function).
>
> OK, this is really in reply to the 4.8 thing, but it felt more
> appropriate here.
>
> It's interesting that you gave this example, since before you were
> complaining about too many fused ops.  Clearly this one could be
> removed in favour of separate and() and not() operations, but why
> not provide a fused one if there are clients who'll make use of it?

I was more concerned about fused operations that use precision
or bitsize as input.  That is for example

>> +  bool only_sign_bit_p (unsigned int prec) const;
>> +  bool only_sign_bit_p () const;

The first is construct a wide-int with precision prec (and sign- or
zero-extend it) and then call only_sign_bit_p on it.  Such function
should not be necessary and existing callers should be questioned
instead of introducing it.

In fact wide-int seems to have so many "fused" operations that
we run out of sensible recognizable names for them.  Which results
in a lot of confusion on what the functions actually do (at least for me).

> I think Kenny's API is just taking that to its logical conclusion.
> There doesn't seem to be anything sacrosanct about the current choice
> of what's fused and what isn't.

Maybe.  I'd rather have seen an initial small wide-int API and fused
operations introduced separately together with the places they are
used.  In the current way it's way too tedious to go over all of them
and match them with callers, lookup enough context and then
make up my mind on whether the caller should do sth different or not.

Thus, consider the big initial API a reason that all this review takes
so long ...

> The speed problem we had using trees for internal arithmetic isn't
> IMO a good argument for keeping double_int in preference to wide_int.
> Allocating and constructing tree objects to hold temporary values,
> storing an integer representation in it, then calling tree arithmetic
> routines that pull out the integer representation again and create a
> tree to hold the result, is going to be much slower than using either
> double_int or wide_int.  I'd be very surprised if we notice any
> measurable difference between double_int and wide_int here.
>
> I still see no reason to keep double_int around.  The width of a host
> wide integer really shouldn't have any significance.
>
> Your main complaint seems to be that the wide_int API is different
> from the double_int one, but we can't literally use the same API, since
> double_int has an implicit precision and bitsize, and wide_int doesn't.
> Having a precision that is separate from the underlying representation
> is IMO the most important feature of wide_int, so:
>
>    template wide_int<2> double_int;
>
> is never going to be a drop-in, API-compatible replacement for double_int.

My reasoning was that if you strip wide-int of precision and bitsize
you have a double_int<N> class.  Thus wide-int should have a base
of that kind and just add precision / bitsize ontop of that.  It wouldn't
be a step forward if we end up replacing double_int uses with
wide_int uses with precision of 2 * HOST_BITS_PER_WIDE_INT,
would it?

> FWIW, I like the idea about having a class that wraps up the mode,
> tree, and (precision, bitsize) choice.

Yeah, if just to make the API look leaner.

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 12:01                                                           ` Richard Biener
@ 2012-10-31 12:12                                                             ` Richard Sandiford
  2012-10-31 12:14                                                               ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2012-10-31 12:12 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl

Richard Biener <richard.guenther@gmail.com> writes:
> On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
>>> <zadeck@naturalbridge.com> wrote:
>>>>
>>>> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>>>>
>>>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump <mikestump@comcast.net> wrote:
>>>>>>
>>>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guenther@gmail.com>
>>>>>> wrote:
>>>>>>>
>>>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>
>>>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>>>>
>>>>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>>>>
>>>>>>>>> are we sure this rounds properly?  Consider a port with max byte mode
>>>>>>>>> size 4 on a 64bit host.
>>>>>>>>
>>>>>>>> I do not believe that this can happen.   The core compiler includes all
>>>>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>>>>
>>>>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>>>>
>>>>>> Actually, no, they are not.  Partial int modes can have bit sizes that
>>>>>> are not power of two, and, if there isn't an int mode that is bigger, we'd
>>>>>> want to round up the partial int bit size.  Something like ((2 *
>>>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>>>>> HOST_BITS_PER_WIDE_INT should do it.
>>>>>>
>>>>>>>>> I still would like to have the ability to provide specializations of
>>>>>>>>> wide_int
>>>>>>>>> for "small" sizes, thus ideally wide_int would be a template templated
>>>>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>>>>>>>>> identical to double_int, thus we should be able to do
>>>>>>>>>
>>>>>>>>> typedef wide_int<2> double_int;
>>>>>>>>
>>>>>>>> If you want to go down this path after the patches get in, go for it.
>>>>>>>> I
>>>>>>>> see no use at all for this.
>>>>>>>> This was not meant to be a plug in replacement for double int. This
>>>>>>>> goal of
>>>>>>>> this patch is to get the compiler to do the constant math the way that
>>>>>>>> the
>>>>>>>> target does it.   Any such instantiation is by definition placing some
>>>>>>>> predefined limit that some target may not want.
>>>>>>>
>>>>>>> Well, what I don't really like is that we now have two implementations
>>>>>>> of functions that perform integer math on two-HWI sized integers.  What
>>>>>>> I also don't like too much is that we have two different interfaces to
>>>>>>> operate
>>>>>>> on them!  Can't you see how I come to not liking this?  Especially the
>>>>>>> latter …
>>>>>>
>>>>>> double_int is logically dead.  Reactoring wide-int and double-int is a
>>>>>> waste of time, as the time is better spent removing double-int from the
>>>>>> compiler.  All the necessary semantics and code of double-int _has_ been
>>>>>> refactored into wide-int already.  Changing wide-int in any way to vend
>>>>>> anything to double-int is wrong, as once double-int is removed,
>>>>>> then all the
>>>>>> api changes to make double-int share from wide-int is wasted and must then
>>>>>> be removed.  The path forward is the complete removal of double-int; it is
>>>>>> wrong, has been wrong and always will be wrong, nothing can change that.
>>>>>
>>>>> double_int, compared to wide_int, is fast and lean.  I doubt we will
>>>>> get rid of it - you
>>>>> will make compile-time math a _lot_ slower.  Just profile when you for
>>>>> example
>>>>> change get_inner_reference to use wide_ints.
>>>>>
>>>>> To be able to remove double_int in favor of wide_int requires _at least_
>>>>> templating wide_int on 'len' and providing specializations for 1 and 2.
>>>>>
>>>>> It might be a non-issue for math that operates on trees or RTXen due to
>>>>> the allocation overhead we pay, but in recent years we transitioned
>>>>> important
>>>>> paths away from using tree math to using double_ints _for speed reasons_.
>>>>>
>>>>> Richard.
>>>>
>>>> i do not know why you believe this about the speed.     double int always
>>>> does synthetic math since you do everything at 128 bit precision.
>>>>
>>>> the thing about wide int, is that since it does math to the precision's
>>>> size, it almost never does uses synthetic operations since the sizes for
>>>> almost every instance can be done using the native math on the machine.
>>>> almost every call has a check to see if the operation can be done natively.
>>>> I seriously doubt that you are going to do TI mode math much faster than i
>>>> do it and if you do who cares.
>>>>
>>>> the number of calls does not effect the performance in any negative way and
>>>> it fact is more efficient since common things that require more than one
>>>> operation in double in are typically done in a single operation.
>>>
>>> Simple double-int operations like
>>>
>>> inline double_int
>>> double_int::and_not (double_int b) const
>>> {
>>>   double_int result;
>>>   result.low = low & ~b.low;
>>>   result.high = high & ~b.high;
>>>   return result;
>>> }
>>>
>>> are always going to be faster than conditionally executing only one operation
>>> (but inside an offline function).
>>
>> OK, this is really in reply to the 4.8 thing, but it felt more
>> appropriate here.
>>
>> It's interesting that you gave this example, since before you were
>> complaining about too many fused ops.  Clearly this one could be
>> removed in favour of separate and() and not() operations, but why
>> not provide a fused one if there are clients who'll make use of it?
>
> I was more concerned about fused operations that use precision
> or bitsize as input.  That is for example
>
>>> +  bool only_sign_bit_p (unsigned int prec) const;
>>> +  bool only_sign_bit_p () const;
>
> The first is construct a wide-int with precision prec (and sign- or
> zero-extend it) and then call only_sign_bit_p on it.  Such function
> should not be necessary and existing callers should be questioned
> instead of introducing it.
>
> In fact wide-int seems to have so many "fused" operations that
> we run out of sensible recognizable names for them.  Which results
> in a lot of confusion on what the functions actually do (at least for me).

Well, I suppose I can't really say anything useful either way on
that one, since I'm not writing the patch and I'm not reviewing it :-)

>> I think Kenny's API is just taking that to its logical conclusion.
>> There doesn't seem to be anything sacrosanct about the current choice
>> of what's fused and what isn't.
>
> Maybe.  I'd rather have seen an initial small wide-int API and fused
> operations introduced separately together with the places they are
> used.  In the current way it's way too tedious to go over all of them
> and match them with callers, lookup enough context and then
> make up my mind on whether the caller should do sth different or not.
>
> Thus, consider the big initial API a reason that all this review takes
> so long ...
>
>> The speed problem we had using trees for internal arithmetic isn't
>> IMO a good argument for keeping double_int in preference to wide_int.
>> Allocating and constructing tree objects to hold temporary values,
>> storing an integer representation in it, then calling tree arithmetic
>> routines that pull out the integer representation again and create a
>> tree to hold the result, is going to be much slower than using either
>> double_int or wide_int.  I'd be very surprised if we notice any
>> measurable difference between double_int and wide_int here.
>>
>> I still see no reason to keep double_int around.  The width of a host
>> wide integer really shouldn't have any significance.
>>
>> Your main complaint seems to be that the wide_int API is different
>> from the double_int one, but we can't literally use the same API, since
>> double_int has an implicit precision and bitsize, and wide_int doesn't.
>> Having a precision that is separate from the underlying representation
>> is IMO the most important feature of wide_int, so:
>>
>>    template wide_int<2> double_int;
>>
>> is never going to be a drop-in, API-compatible replacement for double_int.
>
> My reasoning was that if you strip wide-int of precision and bitsize
> you have a double_int<N> class.

But you don't!  Because...

> Thus wide-int should have a base
> of that kind and just add precision / bitsize ontop of that.  It wouldn't
> be a step forward if we end up replacing double_int uses with
> wide_int uses with precision of 2 * HOST_BITS_PER_WIDE_INT,
> would it?

...the precision and bitsize isn't an optional extra, either conceptually
or in implementation.  wide_int happens to use N HOST_WIDE_INTS under
the hood, but the value of N is an internal implementation detail.
No operations are done to N HWIs, they're done to the number of bits
in the operands.  Whereas a double_int<N> class does everything to N HWIs.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 12:12                                                             ` Richard Sandiford
@ 2012-10-31 12:14                                                               ` Richard Biener
  2012-10-31 12:23                                                                 ` Richard Sandiford
  2012-10-31 13:54                                                                 ` Kenneth Zadeck
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Biener @ 2012-10-31 12:14 UTC (permalink / raw)
  To: Richard Biener, Kenneth Zadeck, Mike Stump, gcc-patches,
	Lawrence Crowl, rdsandiford

On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>> On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford
>> <rdsandiford@googlemail.com> wrote:
>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
>>>> <zadeck@naturalbridge.com> wrote:
>>>>>
>>>>> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>>>>>
>>>>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump <mikestump@comcast.net> wrote:
>>>>>>>
>>>>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guenther@gmail.com>
>>>>>>> wrote:
>>>>>>>>
>>>>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>
>>>>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>>>>>
>>>>>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>>>>>
>>>>>>>>>> are we sure this rounds properly?  Consider a port with max byte mode
>>>>>>>>>> size 4 on a 64bit host.
>>>>>>>>>
>>>>>>>>> I do not believe that this can happen.   The core compiler includes all
>>>>>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>>>>>
>>>>>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>>>>>
>>>>>>> Actually, no, they are not.  Partial int modes can have bit sizes that
>>>>>>> are not power of two, and, if there isn't an int mode that is bigger, we'd
>>>>>>> want to round up the partial int bit size.  Something like ((2 *
>>>>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>>>>>> HOST_BITS_PER_WIDE_INT should do it.
>>>>>>>
>>>>>>>>>> I still would like to have the ability to provide specializations of
>>>>>>>>>> wide_int
>>>>>>>>>> for "small" sizes, thus ideally wide_int would be a template templated
>>>>>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>>>>>>>>>> identical to double_int, thus we should be able to do
>>>>>>>>>>
>>>>>>>>>> typedef wide_int<2> double_int;
>>>>>>>>>
>>>>>>>>> If you want to go down this path after the patches get in, go for it.
>>>>>>>>> I
>>>>>>>>> see no use at all for this.
>>>>>>>>> This was not meant to be a plug in replacement for double int. This
>>>>>>>>> goal of
>>>>>>>>> this patch is to get the compiler to do the constant math the way that
>>>>>>>>> the
>>>>>>>>> target does it.   Any such instantiation is by definition placing some
>>>>>>>>> predefined limit that some target may not want.
>>>>>>>>
>>>>>>>> Well, what I don't really like is that we now have two implementations
>>>>>>>> of functions that perform integer math on two-HWI sized integers.  What
>>>>>>>> I also don't like too much is that we have two different interfaces to
>>>>>>>> operate
>>>>>>>> on them!  Can't you see how I come to not liking this?  Especially the
>>>>>>>> latter …
>>>>>>>
>>>>>>> double_int is logically dead.  Reactoring wide-int and double-int is a
>>>>>>> waste of time, as the time is better spent removing double-int from the
>>>>>>> compiler.  All the necessary semantics and code of double-int _has_ been
>>>>>>> refactored into wide-int already.  Changing wide-int in any way to vend
>>>>>>> anything to double-int is wrong, as once double-int is removed,
>>>>>>> then all the
>>>>>>> api changes to make double-int share from wide-int is wasted and must then
>>>>>>> be removed.  The path forward is the complete removal of double-int; it is
>>>>>>> wrong, has been wrong and always will be wrong, nothing can change that.
>>>>>>
>>>>>> double_int, compared to wide_int, is fast and lean.  I doubt we will
>>>>>> get rid of it - you
>>>>>> will make compile-time math a _lot_ slower.  Just profile when you for
>>>>>> example
>>>>>> change get_inner_reference to use wide_ints.
>>>>>>
>>>>>> To be able to remove double_int in favor of wide_int requires _at least_
>>>>>> templating wide_int on 'len' and providing specializations for 1 and 2.
>>>>>>
>>>>>> It might be a non-issue for math that operates on trees or RTXen due to
>>>>>> the allocation overhead we pay, but in recent years we transitioned
>>>>>> important
>>>>>> paths away from using tree math to using double_ints _for speed reasons_.
>>>>>>
>>>>>> Richard.
>>>>>
>>>>> i do not know why you believe this about the speed.     double int always
>>>>> does synthetic math since you do everything at 128 bit precision.
>>>>>
>>>>> the thing about wide int, is that since it does math to the precision's
>>>>> size, it almost never does uses synthetic operations since the sizes for
>>>>> almost every instance can be done using the native math on the machine.
>>>>> almost every call has a check to see if the operation can be done natively.
>>>>> I seriously doubt that you are going to do TI mode math much faster than i
>>>>> do it and if you do who cares.
>>>>>
>>>>> the number of calls does not effect the performance in any negative way and
>>>>> it fact is more efficient since common things that require more than one
>>>>> operation in double in are typically done in a single operation.
>>>>
>>>> Simple double-int operations like
>>>>
>>>> inline double_int
>>>> double_int::and_not (double_int b) const
>>>> {
>>>>   double_int result;
>>>>   result.low = low & ~b.low;
>>>>   result.high = high & ~b.high;
>>>>   return result;
>>>> }
>>>>
>>>> are always going to be faster than conditionally executing only one operation
>>>> (but inside an offline function).
>>>
>>> OK, this is really in reply to the 4.8 thing, but it felt more
>>> appropriate here.
>>>
>>> It's interesting that you gave this example, since before you were
>>> complaining about too many fused ops.  Clearly this one could be
>>> removed in favour of separate and() and not() operations, but why
>>> not provide a fused one if there are clients who'll make use of it?
>>
>> I was more concerned about fused operations that use precision
>> or bitsize as input.  That is for example
>>
>>>> +  bool only_sign_bit_p (unsigned int prec) const;
>>>> +  bool only_sign_bit_p () const;
>>
>> The first is construct a wide-int with precision prec (and sign- or
>> zero-extend it) and then call only_sign_bit_p on it.  Such function
>> should not be necessary and existing callers should be questioned
>> instead of introducing it.
>>
>> In fact wide-int seems to have so many "fused" operations that
>> we run out of sensible recognizable names for them.  Which results
>> in a lot of confusion on what the functions actually do (at least for me).
>
> Well, I suppose I can't really say anything useful either way on
> that one, since I'm not writing the patch and I'm not reviewing it :-)
>
>>> I think Kenny's API is just taking that to its logical conclusion.
>>> There doesn't seem to be anything sacrosanct about the current choice
>>> of what's fused and what isn't.
>>
>> Maybe.  I'd rather have seen an initial small wide-int API and fused
>> operations introduced separately together with the places they are
>> used.  In the current way it's way too tedious to go over all of them
>> and match them with callers, lookup enough context and then
>> make up my mind on whether the caller should do sth different or not.
>>
>> Thus, consider the big initial API a reason that all this review takes
>> so long ...
>>
>>> The speed problem we had using trees for internal arithmetic isn't
>>> IMO a good argument for keeping double_int in preference to wide_int.
>>> Allocating and constructing tree objects to hold temporary values,
>>> storing an integer representation in it, then calling tree arithmetic
>>> routines that pull out the integer representation again and create a
>>> tree to hold the result, is going to be much slower than using either
>>> double_int or wide_int.  I'd be very surprised if we notice any
>>> measurable difference between double_int and wide_int here.
>>>
>>> I still see no reason to keep double_int around.  The width of a host
>>> wide integer really shouldn't have any significance.
>>>
>>> Your main complaint seems to be that the wide_int API is different
>>> from the double_int one, but we can't literally use the same API, since
>>> double_int has an implicit precision and bitsize, and wide_int doesn't.
>>> Having a precision that is separate from the underlying representation
>>> is IMO the most important feature of wide_int, so:
>>>
>>>    template wide_int<2> double_int;
>>>
>>> is never going to be a drop-in, API-compatible replacement for double_int.
>>
>> My reasoning was that if you strip wide-int of precision and bitsize
>> you have a double_int<N> class.
>
> But you don't!  Because...
>
>> Thus wide-int should have a base
>> of that kind and just add precision / bitsize ontop of that.  It wouldn't
>> be a step forward if we end up replacing double_int uses with
>> wide_int uses with precision of 2 * HOST_BITS_PER_WIDE_INT,
>> would it?
>
> ...the precision and bitsize isn't an optional extra, either conceptually
> or in implementation.  wide_int happens to use N HOST_WIDE_INTS under
> the hood, but the value of N is an internal implementation detail.
> No operations are done to N HWIs, they're done to the number of bits
> in the operands.  Whereas a double_int<N> class does everything to N HWIs.

If that's the only effect then either bitsize or precision is redundant (and
we also have len ...).  Note I did not mention len above, thus the base
class would retain 'len' and double-int would simply use 2 for it
(if you don't template it but make it variable).

Richard.


> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 12:14                                                               ` Richard Biener
@ 2012-10-31 12:23                                                                 ` Richard Sandiford
  2012-10-31 12:50                                                                   ` Richard Biener
  2012-10-31 13:54                                                                 ` Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2012-10-31 12:23 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl

Richard Biener <richard.guenther@gmail.com> writes:
> On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>> On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford
>>> <rdsandiford@googlemail.com> wrote:
>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>
>>>>>> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>>>>>>
>>>>>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump
>>>>>>> <mikestump@comcast.net> wrote:
>>>>>>>>
>>>>>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guenther@gmail.com>
>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>>
>>>>>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>>>>>>
>>>>>>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>>>>>>
>>>>>>>>>>> are we sure this rounds properly?  Consider a port with max byte mode
>>>>>>>>>>> size 4 on a 64bit host.
>>>>>>>>>>
>>>>>>>>>> I do not believe that this can happen.  The core compiler
>>>>>>>>>> includes all
>>>>>>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>>>>>>
>>>>>>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>>>>>>
>>>>>>>> Actually, no, they are not.  Partial int modes can have bit sizes that
>>>>>>>> are not power of two, and, if there isn't an int mode that is
>>>>>>>> bigger, we'd
>>>>>>>> want to round up the partial int bit size.  Something like ((2 *
>>>>>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>>>>>>> HOST_BITS_PER_WIDE_INT should do it.
>>>>>>>>
>>>>>>>>>>> I still would like to have the ability to provide specializations of
>>>>>>>>>>> wide_int
>>>>>>>>>>> for "small" sizes, thus ideally wide_int would be a template
>>>>>>>>>>> templated
>>>>>>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>>>>>>>>>>> identical to double_int, thus we should be able to do
>>>>>>>>>>>
>>>>>>>>>>> typedef wide_int<2> double_int;
>>>>>>>>>>
>>>>>>>>>> If you want to go down this path after the patches get in, go for it.
>>>>>>>>>> I
>>>>>>>>>> see no use at all for this.
>>>>>>>>>> This was not meant to be a plug in replacement for double int. This
>>>>>>>>>> goal of
>>>>>>>>>> this patch is to get the compiler to do the constant math the way that
>>>>>>>>>> the
>>>>>>>>>> target does it.   Any such instantiation is by definition placing some
>>>>>>>>>> predefined limit that some target may not want.
>>>>>>>>>
>>>>>>>>> Well, what I don't really like is that we now have two implementations
>>>>>>>>> of functions that perform integer math on two-HWI sized integers.  What
>>>>>>>>> I also don't like too much is that we have two different interfaces to
>>>>>>>>> operate
>>>>>>>>> on them!  Can't you see how I come to not liking this?  Especially the
>>>>>>>>> latter …
>>>>>>>>
>>>>>>>> double_int is logically dead.  Reactoring wide-int and double-int is a
>>>>>>>> waste of time, as the time is better spent removing double-int from the
>>>>>>>> compiler.  All the necessary semantics and code of double-int _has_ been
>>>>>>>> refactored into wide-int already.  Changing wide-int in any way to vend
>>>>>>>> anything to double-int is wrong, as once double-int is removed,
>>>>>>>> then all the
>>>>>>>> api changes to make double-int share from wide-int is wasted and
>>>>>>>> must then
>>>>>>>> be removed.  The path forward is the complete removal of
>>>>>>>> double-int; it is
>>>>>>>> wrong, has been wrong and always will be wrong, nothing can change that.
>>>>>>>
>>>>>>> double_int, compared to wide_int, is fast and lean.  I doubt we will
>>>>>>> get rid of it - you
>>>>>>> will make compile-time math a _lot_ slower.  Just profile when you for
>>>>>>> example
>>>>>>> change get_inner_reference to use wide_ints.
>>>>>>>
>>>>>>> To be able to remove double_int in favor of wide_int requires _at least_
>>>>>>> templating wide_int on 'len' and providing specializations for 1 and 2.
>>>>>>>
>>>>>>> It might be a non-issue for math that operates on trees or RTXen due to
>>>>>>> the allocation overhead we pay, but in recent years we transitioned
>>>>>>> important
>>>>>>> paths away from using tree math to using double_ints _for speed reasons_.
>>>>>>>
>>>>>>> Richard.
>>>>>>
>>>>>> i do not know why you believe this about the speed.     double int always
>>>>>> does synthetic math since you do everything at 128 bit precision.
>>>>>>
>>>>>> the thing about wide int, is that since it does math to the precision's
>>>>>> size, it almost never does uses synthetic operations since the sizes for
>>>>>> almost every instance can be done using the native math on the machine.
>>>>>> almost every call has a check to see if the operation can be done
>>>>>> natively.
>>>>>> I seriously doubt that you are going to do TI mode math much faster than i
>>>>>> do it and if you do who cares.
>>>>>>
>>>>>> the number of calls does not effect the performance in any
>>>>>> negative way and
>>>>>> it fact is more efficient since common things that require more than one
>>>>>> operation in double in are typically done in a single operation.
>>>>>
>>>>> Simple double-int operations like
>>>>>
>>>>> inline double_int
>>>>> double_int::and_not (double_int b) const
>>>>> {
>>>>>   double_int result;
>>>>>   result.low = low & ~b.low;
>>>>>   result.high = high & ~b.high;
>>>>>   return result;
>>>>> }
>>>>>
>>>>> are always going to be faster than conditionally executing only one
>>>>> operation
>>>>> (but inside an offline function).
>>>>
>>>> OK, this is really in reply to the 4.8 thing, but it felt more
>>>> appropriate here.
>>>>
>>>> It's interesting that you gave this example, since before you were
>>>> complaining about too many fused ops.  Clearly this one could be
>>>> removed in favour of separate and() and not() operations, but why
>>>> not provide a fused one if there are clients who'll make use of it?
>>>
>>> I was more concerned about fused operations that use precision
>>> or bitsize as input.  That is for example
>>>
>>>>> +  bool only_sign_bit_p (unsigned int prec) const;
>>>>> +  bool only_sign_bit_p () const;
>>>
>>> The first is construct a wide-int with precision prec (and sign- or
>>> zero-extend it) and then call only_sign_bit_p on it.  Such function
>>> should not be necessary and existing callers should be questioned
>>> instead of introducing it.
>>>
>>> In fact wide-int seems to have so many "fused" operations that
>>> we run out of sensible recognizable names for them.  Which results
>>> in a lot of confusion on what the functions actually do (at least for me).
>>
>> Well, I suppose I can't really say anything useful either way on
>> that one, since I'm not writing the patch and I'm not reviewing it :-)
>>
>>>> I think Kenny's API is just taking that to its logical conclusion.
>>>> There doesn't seem to be anything sacrosanct about the current choice
>>>> of what's fused and what isn't.
>>>
>>> Maybe.  I'd rather have seen an initial small wide-int API and fused
>>> operations introduced separately together with the places they are
>>> used.  In the current way it's way too tedious to go over all of them
>>> and match them with callers, lookup enough context and then
>>> make up my mind on whether the caller should do sth different or not.
>>>
>>> Thus, consider the big initial API a reason that all this review takes
>>> so long ...
>>>
>>>> The speed problem we had using trees for internal arithmetic isn't
>>>> IMO a good argument for keeping double_int in preference to wide_int.
>>>> Allocating and constructing tree objects to hold temporary values,
>>>> storing an integer representation in it, then calling tree arithmetic
>>>> routines that pull out the integer representation again and create a
>>>> tree to hold the result, is going to be much slower than using either
>>>> double_int or wide_int.  I'd be very surprised if we notice any
>>>> measurable difference between double_int and wide_int here.
>>>>
>>>> I still see no reason to keep double_int around.  The width of a host
>>>> wide integer really shouldn't have any significance.
>>>>
>>>> Your main complaint seems to be that the wide_int API is different
>>>> from the double_int one, but we can't literally use the same API, since
>>>> double_int has an implicit precision and bitsize, and wide_int doesn't.
>>>> Having a precision that is separate from the underlying representation
>>>> is IMO the most important feature of wide_int, so:
>>>>
>>>>    template wide_int<2> double_int;
>>>>
>>>> is never going to be a drop-in, API-compatible replacement for double_int.
>>>
>>> My reasoning was that if you strip wide-int of precision and bitsize
>>> you have a double_int<N> class.
>>
>> But you don't!  Because...
>>
>>> Thus wide-int should have a base
>>> of that kind and just add precision / bitsize ontop of that.  It wouldn't
>>> be a step forward if we end up replacing double_int uses with
>>> wide_int uses with precision of 2 * HOST_BITS_PER_WIDE_INT,
>>> would it?
>>
>> ...the precision and bitsize isn't an optional extra, either conceptually
>> or in implementation.  wide_int happens to use N HOST_WIDE_INTS under
>> the hood, but the value of N is an internal implementation detail.
>> No operations are done to N HWIs, they're done to the number of bits
>> in the operands.  Whereas a double_int<N> class does everything to N HWIs.
>
> If that's the only effect then either bitsize or precision is redundant (and
> we also have len ...).  Note I did not mention len above, thus the base
> class would retain 'len' and double-int would simply use 2 for it
> (if you don't template it but make it variable).

But that means that wide_int has to model a P-bit operation as a
"normal" len*HOST_WIDE_INT operation and then fix up the result
after the fact, which seems unnecessarily convoluted.  I still don't
see why a full-precision 2*HOST_WIDE_INT operation (or a full-precision
X*HOST_WIDE_INT operation for any X) has any special meaning.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 12:23                                                                 ` Richard Sandiford
@ 2012-10-31 12:50                                                                   ` Richard Biener
  2012-10-31 13:50                                                                     ` Richard Sandiford
                                                                                       ` (2 more replies)
  0 siblings, 3 replies; 217+ messages in thread
From: Richard Biener @ 2012-10-31 12:50 UTC (permalink / raw)
  To: Richard Biener, Kenneth Zadeck, Mike Stump, gcc-patches,
	Lawrence Crowl, rdsandiford

On Wed, Oct 31, 2012 at 1:22 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>> On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford
>> <rdsandiford@googlemail.com> wrote:
>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>> On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford
>>>> <rdsandiford@googlemail.com> wrote:
>>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>
>>>>>>> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>>>>>>>
>>>>>>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump
>>>>>>>> <mikestump@comcast.net> wrote:
>>>>>>>>>
>>>>>>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guenther@gmail.com>
>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>>>
>>>>>>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>>>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>>>>>>>
>>>>>>>>>>>> are we sure this rounds properly?  Consider a port with max byte mode
>>>>>>>>>>>> size 4 on a 64bit host.
>>>>>>>>>>>
>>>>>>>>>>> I do not believe that this can happen.  The core compiler
>>>>>>>>>>> includes all
>>>>>>>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>>>>>>>
>>>>>>>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>>>>>>>
>>>>>>>>> Actually, no, they are not.  Partial int modes can have bit sizes that
>>>>>>>>> are not power of two, and, if there isn't an int mode that is
>>>>>>>>> bigger, we'd
>>>>>>>>> want to round up the partial int bit size.  Something like ((2 *
>>>>>>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>>>>>>>> HOST_BITS_PER_WIDE_INT should do it.
>>>>>>>>>
>>>>>>>>>>>> I still would like to have the ability to provide specializations of
>>>>>>>>>>>> wide_int
>>>>>>>>>>>> for "small" sizes, thus ideally wide_int would be a template
>>>>>>>>>>>> templated
>>>>>>>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>>>>>>>>>>>> identical to double_int, thus we should be able to do
>>>>>>>>>>>>
>>>>>>>>>>>> typedef wide_int<2> double_int;
>>>>>>>>>>>
>>>>>>>>>>> If you want to go down this path after the patches get in, go for it.
>>>>>>>>>>> I
>>>>>>>>>>> see no use at all for this.
>>>>>>>>>>> This was not meant to be a plug in replacement for double int. This
>>>>>>>>>>> goal of
>>>>>>>>>>> this patch is to get the compiler to do the constant math the way that
>>>>>>>>>>> the
>>>>>>>>>>> target does it.   Any such instantiation is by definition placing some
>>>>>>>>>>> predefined limit that some target may not want.
>>>>>>>>>>
>>>>>>>>>> Well, what I don't really like is that we now have two implementations
>>>>>>>>>> of functions that perform integer math on two-HWI sized integers.  What
>>>>>>>>>> I also don't like too much is that we have two different interfaces to
>>>>>>>>>> operate
>>>>>>>>>> on them!  Can't you see how I come to not liking this?  Especially the
>>>>>>>>>> latter …
>>>>>>>>>
>>>>>>>>> double_int is logically dead.  Reactoring wide-int and double-int is a
>>>>>>>>> waste of time, as the time is better spent removing double-int from the
>>>>>>>>> compiler.  All the necessary semantics and code of double-int _has_ been
>>>>>>>>> refactored into wide-int already.  Changing wide-int in any way to vend
>>>>>>>>> anything to double-int is wrong, as once double-int is removed,
>>>>>>>>> then all the
>>>>>>>>> api changes to make double-int share from wide-int is wasted and
>>>>>>>>> must then
>>>>>>>>> be removed.  The path forward is the complete removal of
>>>>>>>>> double-int; it is
>>>>>>>>> wrong, has been wrong and always will be wrong, nothing can change that.
>>>>>>>>
>>>>>>>> double_int, compared to wide_int, is fast and lean.  I doubt we will
>>>>>>>> get rid of it - you
>>>>>>>> will make compile-time math a _lot_ slower.  Just profile when you for
>>>>>>>> example
>>>>>>>> change get_inner_reference to use wide_ints.
>>>>>>>>
>>>>>>>> To be able to remove double_int in favor of wide_int requires _at least_
>>>>>>>> templating wide_int on 'len' and providing specializations for 1 and 2.
>>>>>>>>
>>>>>>>> It might be a non-issue for math that operates on trees or RTXen due to
>>>>>>>> the allocation overhead we pay, but in recent years we transitioned
>>>>>>>> important
>>>>>>>> paths away from using tree math to using double_ints _for speed reasons_.
>>>>>>>>
>>>>>>>> Richard.
>>>>>>>
>>>>>>> i do not know why you believe this about the speed.     double int always
>>>>>>> does synthetic math since you do everything at 128 bit precision.
>>>>>>>
>>>>>>> the thing about wide int, is that since it does math to the precision's
>>>>>>> size, it almost never does uses synthetic operations since the sizes for
>>>>>>> almost every instance can be done using the native math on the machine.
>>>>>>> almost every call has a check to see if the operation can be done
>>>>>>> natively.
>>>>>>> I seriously doubt that you are going to do TI mode math much faster than i
>>>>>>> do it and if you do who cares.
>>>>>>>
>>>>>>> the number of calls does not effect the performance in any
>>>>>>> negative way and
>>>>>>> it fact is more efficient since common things that require more than one
>>>>>>> operation in double in are typically done in a single operation.
>>>>>>
>>>>>> Simple double-int operations like
>>>>>>
>>>>>> inline double_int
>>>>>> double_int::and_not (double_int b) const
>>>>>> {
>>>>>>   double_int result;
>>>>>>   result.low = low & ~b.low;
>>>>>>   result.high = high & ~b.high;
>>>>>>   return result;
>>>>>> }
>>>>>>
>>>>>> are always going to be faster than conditionally executing only one
>>>>>> operation
>>>>>> (but inside an offline function).
>>>>>
>>>>> OK, this is really in reply to the 4.8 thing, but it felt more
>>>>> appropriate here.
>>>>>
>>>>> It's interesting that you gave this example, since before you were
>>>>> complaining about too many fused ops.  Clearly this one could be
>>>>> removed in favour of separate and() and not() operations, but why
>>>>> not provide a fused one if there are clients who'll make use of it?
>>>>
>>>> I was more concerned about fused operations that use precision
>>>> or bitsize as input.  That is for example
>>>>
>>>>>> +  bool only_sign_bit_p (unsigned int prec) const;
>>>>>> +  bool only_sign_bit_p () const;
>>>>
>>>> The first is construct a wide-int with precision prec (and sign- or
>>>> zero-extend it) and then call only_sign_bit_p on it.  Such function
>>>> should not be necessary and existing callers should be questioned
>>>> instead of introducing it.
>>>>
>>>> In fact wide-int seems to have so many "fused" operations that
>>>> we run out of sensible recognizable names for them.  Which results
>>>> in a lot of confusion on what the functions actually do (at least for me).
>>>
>>> Well, I suppose I can't really say anything useful either way on
>>> that one, since I'm not writing the patch and I'm not reviewing it :-)
>>>
>>>>> I think Kenny's API is just taking that to its logical conclusion.
>>>>> There doesn't seem to be anything sacrosanct about the current choice
>>>>> of what's fused and what isn't.
>>>>
>>>> Maybe.  I'd rather have seen an initial small wide-int API and fused
>>>> operations introduced separately together with the places they are
>>>> used.  In the current way it's way too tedious to go over all of them
>>>> and match them with callers, lookup enough context and then
>>>> make up my mind on whether the caller should do sth different or not.
>>>>
>>>> Thus, consider the big initial API a reason that all this review takes
>>>> so long ...
>>>>
>>>>> The speed problem we had using trees for internal arithmetic isn't
>>>>> IMO a good argument for keeping double_int in preference to wide_int.
>>>>> Allocating and constructing tree objects to hold temporary values,
>>>>> storing an integer representation in it, then calling tree arithmetic
>>>>> routines that pull out the integer representation again and create a
>>>>> tree to hold the result, is going to be much slower than using either
>>>>> double_int or wide_int.  I'd be very surprised if we notice any
>>>>> measurable difference between double_int and wide_int here.
>>>>>
>>>>> I still see no reason to keep double_int around.  The width of a host
>>>>> wide integer really shouldn't have any significance.
>>>>>
>>>>> Your main complaint seems to be that the wide_int API is different
>>>>> from the double_int one, but we can't literally use the same API, since
>>>>> double_int has an implicit precision and bitsize, and wide_int doesn't.
>>>>> Having a precision that is separate from the underlying representation
>>>>> is IMO the most important feature of wide_int, so:
>>>>>
>>>>>    template wide_int<2> double_int;
>>>>>
>>>>> is never going to be a drop-in, API-compatible replacement for double_int.
>>>>
>>>> My reasoning was that if you strip wide-int of precision and bitsize
>>>> you have a double_int<N> class.
>>>
>>> But you don't!  Because...
>>>
>>>> Thus wide-int should have a base
>>>> of that kind and just add precision / bitsize ontop of that.  It wouldn't
>>>> be a step forward if we end up replacing double_int uses with
>>>> wide_int uses with precision of 2 * HOST_BITS_PER_WIDE_INT,
>>>> would it?
>>>
>>> ...the precision and bitsize isn't an optional extra, either conceptually
>>> or in implementation.  wide_int happens to use N HOST_WIDE_INTS under
>>> the hood, but the value of N is an internal implementation detail.
>>> No operations are done to N HWIs, they're done to the number of bits
>>> in the operands.  Whereas a double_int<N> class does everything to N HWIs.
>>
>> If that's the only effect then either bitsize or precision is redundant (and
>> we also have len ...).  Note I did not mention len above, thus the base
>> class would retain 'len' and double-int would simply use 2 for it
>> (if you don't template it but make it variable).
>
> But that means that wide_int has to model a P-bit operation as a
> "normal" len*HOST_WIDE_INT operation and then fix up the result
> after the fact, which seems unnecessarily convoluted.

It does that right now.  The operations are carried out in a loop
over len HOST_WIDE_INT parts, the last HWI is then special-treated
to account for precision/size.  (yes, 'len' is also used as optimization - the
fact that len ends up being mutable is another thing I dislike about
wide-int.  If wide-ints are cheap then all ops should be non-mutating
(at least to 'len')).

>  I still don't
> see why a full-precision 2*HOST_WIDE_INT operation (or a full-precision
> X*HOST_WIDE_INT operation for any X) has any special meaning.

Well, the same reason as a HOST_WIDE_INT variable has a meaning.
We use it to constrain what we (efficiently) want to work on.  For example
CCP might iterate up to 2 * HOST_BITS_PER_WIDE_INT times when
doing bit-constant-propagation in loops (for TImode integers on a x86_64 host).

Oh, and I don't necessary see a use of double_int in its current form
but for an integer representation on the host that is efficient to manipulate
integer constants of a target dependent size.  For example the target
detail that we have partial integer modes with bitsize > precision and that
the bits > precision appearantly have a meaning when looking at the
bit-representation of a constant should not be part of the base class
of wide-int (I doubt it belongs to wide-int at all, but I guess you know more
about the reason we track bitsize in addition to precision - I think it's
abstraction at the wrong level, the tree level does fine without knowing
about bitsize).

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 12:50                                                                   ` Richard Biener
@ 2012-10-31 13:50                                                                     ` Richard Sandiford
  2012-10-31 13:56                                                                       ` Richard Biener
  2012-10-31 15:52                                                                       ` Kenneth Zadeck
  2012-10-31 14:39                                                                     ` Kenneth Zadeck
  2012-10-31 19:22                                                                     ` Mike Stump
  2 siblings, 2 replies; 217+ messages in thread
From: Richard Sandiford @ 2012-10-31 13:50 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl

Richard Biener <richard.guenther@gmail.com> writes:
>> But that means that wide_int has to model a P-bit operation as a
>> "normal" len*HOST_WIDE_INT operation and then fix up the result
>> after the fact, which seems unnecessarily convoluted.
>
> It does that right now.  The operations are carried out in a loop
> over len HOST_WIDE_INT parts, the last HWI is then special-treated
> to account for precision/size.  (yes, 'len' is also used as optimization - the
> fact that len ends up being mutable is another thing I dislike about
> wide-int.  If wide-ints are cheap then all ops should be non-mutating
> (at least to 'len')).

But the point of having a mutating len is that things like zero and -1
are common even for OImode values.  So if you're doing someting potentially
expensive like OImode multiplication, why do it to the number of
HOST_WIDE_INTs needed for an OImode value when the value we're
processing has only one significant HOST_WIDE_INT?

>>  I still don't
>> see why a full-precision 2*HOST_WIDE_INT operation (or a full-precision
>> X*HOST_WIDE_INT operation for any X) has any special meaning.
>
> Well, the same reason as a HOST_WIDE_INT variable has a meaning.
> We use it to constrain what we (efficiently) want to work on.  For example
> CCP might iterate up to 2 * HOST_BITS_PER_WIDE_INT times when
> doing bit-constant-propagation in loops (for TImode integers on a x86_64 host).

But what about targets with modes wider than TImode?  Would double_int
still be appropriate then?  If not, why does CCP have to use a templated
type with a fixed number of HWIs (and all arithmetic done to a fixed
number of HWIs) rather than one that can adapt to the runtime values,
like wide_int can?

> Oh, and I don't necessary see a use of double_int in its current form
> but for an integer representation on the host that is efficient to manipulate
> integer constants of a target dependent size.  For example the target
> detail that we have partial integer modes with bitsize > precision and that
> the bits > precision appearantly have a meaning when looking at the
> bit-representation of a constant should not be part of the base class
> of wide-int (I doubt it belongs to wide-int at all, but I guess you know more
> about the reason we track bitsize in addition to precision - I think it's
> abstraction at the wrong level, the tree level does fine without knowing
> about bitsize).

TBH I'm uneasy about the bitsize thing too.  I think bitsize is only
tracked for shift truncation, and if so, I agree it makes sense
to do that separately.

But anyway, this whole discussion seems to have reached a stalemate.
Or I suppose a de-facto rejection, since you're the only person in
a position to approve the thing :-)

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 12:14                                                               ` Richard Biener
  2012-10-31 12:23                                                                 ` Richard Sandiford
@ 2012-10-31 13:54                                                                 ` Kenneth Zadeck
  2012-10-31 14:07                                                                   ` Richard Biener
  1 sibling, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-31 13:54 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford


On 10/31/2012 08:11 AM, Richard Biener wrote:
> On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>> On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford
>>> <rdsandiford@googlemail.com> wrote:
>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>>>>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump <mikestump@comcast.net> wrote:
>>>>>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guenther@gmail.com>
>>>>>>>> wrote:
>>>>>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>>>>>>
>>>>>>>>>>> are we sure this rounds properly?  Consider a port with max byte mode
>>>>>>>>>>> size 4 on a 64bit host.
>>>>>>>>>> I do not believe that this can happen.   The core compiler includes all
>>>>>>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>>>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>>>>>> Actually, no, they are not.  Partial int modes can have bit sizes that
>>>>>>>> are not power of two, and, if there isn't an int mode that is bigger, we'd
>>>>>>>> want to round up the partial int bit size.  Something like ((2 *
>>>>>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>>>>>>> HOST_BITS_PER_WIDE_INT should do it.
>>>>>>>>
>>>>>>>>>>> I still would like to have the ability to provide specializations of
>>>>>>>>>>> wide_int
>>>>>>>>>>> for "small" sizes, thus ideally wide_int would be a template templated
>>>>>>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>>>>>>>>>>> identical to double_int, thus we should be able to do
>>>>>>>>>>>
>>>>>>>>>>> typedef wide_int<2> double_int;
>>>>>>>>>> If you want to go down this path after the patches get in, go for it.
>>>>>>>>>> I
>>>>>>>>>> see no use at all for this.
>>>>>>>>>> This was not meant to be a plug in replacement for double int. This
>>>>>>>>>> goal of
>>>>>>>>>> this patch is to get the compiler to do the constant math the way that
>>>>>>>>>> the
>>>>>>>>>> target does it.   Any such instantiation is by definition placing some
>>>>>>>>>> predefined limit that some target may not want.
>>>>>>>>> Well, what I don't really like is that we now have two implementations
>>>>>>>>> of functions that perform integer math on two-HWI sized integers.  What
>>>>>>>>> I also don't like too much is that we have two different interfaces to
>>>>>>>>> operate
>>>>>>>>> on them!  Can't you see how I come to not liking this?  Especially the
>>>>>>>>> latter Â…
>>>>>>>> double_int is logically dead.  Reactoring wide-int and double-int is a
>>>>>>>> waste of time, as the time is better spent removing double-int from the
>>>>>>>> compiler.  All the necessary semantics and code of double-int _has_ been
>>>>>>>> refactored into wide-int already.  Changing wide-int in any way to vend
>>>>>>>> anything to double-int is wrong, as once double-int is removed,
>>>>>>>> then all the
>>>>>>>> api changes to make double-int share from wide-int is wasted and must then
>>>>>>>> be removed.  The path forward is the complete removal of double-int; it is
>>>>>>>> wrong, has been wrong and always will be wrong, nothing can change that.
>>>>>>> double_int, compared to wide_int, is fast and lean.  I doubt we will
>>>>>>> get rid of it - you
>>>>>>> will make compile-time math a _lot_ slower.  Just profile when you for
>>>>>>> example
>>>>>>> change get_inner_reference to use wide_ints.
>>>>>>>
>>>>>>> To be able to remove double_int in favor of wide_int requires _at least_
>>>>>>> templating wide_int on 'len' and providing specializations for 1 and 2.
>>>>>>>
>>>>>>> It might be a non-issue for math that operates on trees or RTXen due to
>>>>>>> the allocation overhead we pay, but in recent years we transitioned
>>>>>>> important
>>>>>>> paths away from using tree math to using double_ints _for speed reasons_.
>>>>>>>
>>>>>>> Richard.
>>>>>> i do not know why you believe this about the speed.     double int always
>>>>>> does synthetic math since you do everything at 128 bit precision.
>>>>>>
>>>>>> the thing about wide int, is that since it does math to the precision's
>>>>>> size, it almost never does uses synthetic operations since the sizes for
>>>>>> almost every instance can be done using the native math on the machine.
>>>>>> almost every call has a check to see if the operation can be done natively.
>>>>>> I seriously doubt that you are going to do TI mode math much faster than i
>>>>>> do it and if you do who cares.
>>>>>>
>>>>>> the number of calls does not effect the performance in any negative way and
>>>>>> it fact is more efficient since common things that require more than one
>>>>>> operation in double in are typically done in a single operation.
>>>>> Simple double-int operations like
>>>>>
>>>>> inline double_int
>>>>> double_int::and_not (double_int b) const
>>>>> {
>>>>>    double_int result;
>>>>>    result.low = low & ~b.low;
>>>>>    result.high = high & ~b.high;
>>>>>    return result;
>>>>> }
>>>>>
>>>>> are always going to be faster than conditionally executing only one operation
>>>>> (but inside an offline function).
>>>> OK, this is really in reply to the 4.8 thing, but it felt more
>>>> appropriate here.
>>>>
>>>> It's interesting that you gave this example, since before you were
>>>> complaining about too many fused ops.  Clearly this one could be
>>>> removed in favour of separate and() and not() operations, but why
>>>> not provide a fused one if there are clients who'll make use of it?
>>> I was more concerned about fused operations that use precision
>>> or bitsize as input.  That is for example
>>>
>>>>> +  bool only_sign_bit_p (unsigned int prec) const;
>>>>> +  bool only_sign_bit_p () const;
>>> The first is construct a wide-int with precision prec (and sign- or
>>> zero-extend it) and then call only_sign_bit_p on it.  Such function
>>> should not be necessary and existing callers should be questioned
>>> instead of introducing it.
>>>
>>> In fact wide-int seems to have so many "fused" operations that
>>> we run out of sensible recognizable names for them.  Which results
>>> in a lot of confusion on what the functions actually do (at least for me).
>> Well, I suppose I can't really say anything useful either way on
>> that one, since I'm not writing the patch and I'm not reviewing it :-)
>>
>>>> I think Kenny's API is just taking that to its logical conclusion.
>>>> There doesn't seem to be anything sacrosanct about the current choice
>>>> of what's fused and what isn't.
>>> Maybe.  I'd rather have seen an initial small wide-int API and fused
>>> operations introduced separately together with the places they are
>>> used.  In the current way it's way too tedious to go over all of them
>>> and match them with callers, lookup enough context and then
>>> make up my mind on whether the caller should do sth different or not.
>>>
>>> Thus, consider the big initial API a reason that all this review takes
>>> so long ...
>>>
>>>> The speed problem we had using trees for internal arithmetic isn't
>>>> IMO a good argument for keeping double_int in preference to wide_int.
>>>> Allocating and constructing tree objects to hold temporary values,
>>>> storing an integer representation in it, then calling tree arithmetic
>>>> routines that pull out the integer representation again and create a
>>>> tree to hold the result, is going to be much slower than using either
>>>> double_int or wide_int.  I'd be very surprised if we notice any
>>>> measurable difference between double_int and wide_int here.
>>>>
>>>> I still see no reason to keep double_int around.  The width of a host
>>>> wide integer really shouldn't have any significance.
>>>>
>>>> Your main complaint seems to be that the wide_int API is different
>>>> from the double_int one, but we can't literally use the same API, since
>>>> double_int has an implicit precision and bitsize, and wide_int doesn't.
>>>> Having a precision that is separate from the underlying representation
>>>> is IMO the most important feature of wide_int, so:
>>>>
>>>>     template wide_int<2> double_int;
>>>>
>>>> is never going to be a drop-in, API-compatible replacement for double_int.
>>> My reasoning was that if you strip wide-int of precision and bitsize
>>> you have a double_int<N> class.
>> But you don't!  Because...
>>
>>> Thus wide-int should have a base
>>> of that kind and just add precision / bitsize ontop of that.  It wouldn't
>>> be a step forward if we end up replacing double_int uses with
>>> wide_int uses with precision of 2 * HOST_BITS_PER_WIDE_INT,
>>> would it?
>> ...the precision and bitsize isn't an optional extra, either conceptually
>> or in implementation.  wide_int happens to use N HOST_WIDE_INTS under
>> the hood, but the value of N is an internal implementation detail.
>> No operations are done to N HWIs, they're done to the number of bits
>> in the operands.  Whereas a double_int<N> class does everything to N HWIs.
> If that's the only effect then either bitsize or precision is redundant (and
> we also have len ...).  Note I did not mention len above, thus the base
> class would retain 'len' and double-int would simply use 2 for it
> (if you don't template it but make it variable).
>
> Richard.
>
NO, in your own words, there are two parts of the compiler that want the 
infinite model.   The rest wants to do the math the way the target does 
it.   My version now accommodates both.    In tree vrp it scans the 
gimple and determines what the largest type is and that is the basis of 
all of the math in this pass.  If you just make double int bigger, then 
you are paying for big math everywhere.


>> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 13:50                                                                     ` Richard Sandiford
@ 2012-10-31 13:56                                                                       ` Richard Biener
  2012-10-31 14:26                                                                         ` Kenneth Zadeck
  2012-10-31 19:45                                                                         ` Mike Stump
  2012-10-31 15:52                                                                       ` Kenneth Zadeck
  1 sibling, 2 replies; 217+ messages in thread
From: Richard Biener @ 2012-10-31 13:56 UTC (permalink / raw)
  To: Richard Biener, Kenneth Zadeck, Mike Stump, gcc-patches,
	Lawrence Crowl, rdsandiford

On Wed, Oct 31, 2012 at 2:30 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>>> But that means that wide_int has to model a P-bit operation as a
>>> "normal" len*HOST_WIDE_INT operation and then fix up the result
>>> after the fact, which seems unnecessarily convoluted.
>>
>> It does that right now.  The operations are carried out in a loop
>> over len HOST_WIDE_INT parts, the last HWI is then special-treated
>> to account for precision/size.  (yes, 'len' is also used as optimization - the
>> fact that len ends up being mutable is another thing I dislike about
>> wide-int.  If wide-ints are cheap then all ops should be non-mutating
>> (at least to 'len')).
>
> But the point of having a mutating len is that things like zero and -1
> are common even for OImode values.  So if you're doing someting potentially
> expensive like OImode multiplication, why do it to the number of
> HOST_WIDE_INTs needed for an OImode value when the value we're
> processing has only one significant HOST_WIDE_INT?

I don't propose doing that.  I propose that no wide-int member function
may _change_ it's len (to something larger).  Only that way you can
avoid allocating wasted space for zero and -1.  That way also the
artificial limit on 2 * largest-int-mode-hwis goes.

>>>  I still don't
>>> see why a full-precision 2*HOST_WIDE_INT operation (or a full-precision
>>> X*HOST_WIDE_INT operation for any X) has any special meaning.
>>
>> Well, the same reason as a HOST_WIDE_INT variable has a meaning.
>> We use it to constrain what we (efficiently) want to work on.  For example
>> CCP might iterate up to 2 * HOST_BITS_PER_WIDE_INT times when
>> doing bit-constant-propagation in loops (for TImode integers on a x86_64 host).
>
> But what about targets with modes wider than TImode?  Would double_int
> still be appropriate then?  If not, why does CCP have to use a templated
> type with a fixed number of HWIs (and all arithmetic done to a fixed
> number of HWIs) rather than one that can adapt to the runtime values,
> like wide_int can?

Because nobody cares about accurate bit-tracking for modes larger than
TImode.  And because no convenient abstraction was available ;)

>> Oh, and I don't necessary see a use of double_int in its current form
>> but for an integer representation on the host that is efficient to manipulate
>> integer constants of a target dependent size.  For example the target
>> detail that we have partial integer modes with bitsize > precision and that
>> the bits > precision appearantly have a meaning when looking at the
>> bit-representation of a constant should not be part of the base class
>> of wide-int (I doubt it belongs to wide-int at all, but I guess you know more
>> about the reason we track bitsize in addition to precision - I think it's
>> abstraction at the wrong level, the tree level does fine without knowing
>> about bitsize).
>
> TBH I'm uneasy about the bitsize thing too.  I think bitsize is only
> tracked for shift truncation, and if so, I agree it makes sense
> to do that separately.

So, can we please remove all traces of bitsize from wide-int then?

> But anyway, this whole discussion seems to have reached a stalemate.
> Or I suppose a de-facto rejection, since you're the only person in
> a position to approve the thing :-)

There are many (silent) people that are able to approve the thing.  But the
point is I have too many issues with the current patch that I'm unable
to point at a specific thing I want Kenny to change after which the patch
would be fine.  So I rely on some guesswork from Kenny giving my
advices "leaner API", "less fused ops", "get rid of bitsize", "think of
abstracting the core HWI[len] operation", "there should be no tree or
RTL dependencies in the wide-int API" to produce an updated variant.
Which of course takes time, which of course crosses my vacation, which
in the end means it isn't going to make 4.8 (I _do_ like the idea of not
having a dependence on host properties for integer constant representation).

Btw, a good hint at what a minimal wide-int API would look like is if
you _just_ replace double-int users with it.  Then you obviously have to
implement only the double-int interface and conversion from/to double-int.

Richard.


> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 13:54                                                                 ` Kenneth Zadeck
@ 2012-10-31 14:07                                                                   ` Richard Biener
  2012-10-31 14:25                                                                     ` Kenneth Zadeck
  2012-10-31 20:07                                                                     ` patch to fix constant math - 4th patch - the wide-int class Mike Stump
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Biener @ 2012-10-31 14:07 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford

On Wed, Oct 31, 2012 at 2:54 PM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
>
> On 10/31/2012 08:11 AM, Richard Biener wrote:
>>
>> On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford
>> <rdsandiford@googlemail.com> wrote:
>>>
>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>
>>>> On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford
>>>> <rdsandiford@googlemail.com> wrote:
>>>>>
>>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>>
>>>>>> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>
>>>>>>> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>>>>>>>
>>>>>>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump <mikestump@comcast.net>
>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener
>>>>>>>>> <richard.guenther@gmail.com>
>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>>>
>>>>>>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>>>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>>>>>>>
>>>>>>>>>>>> are we sure this rounds properly?  Consider a port with max byte
>>>>>>>>>>>> mode
>>>>>>>>>>>> size 4 on a 64bit host.
>>>>>>>>>>>
>>>>>>>>>>> I do not believe that this can happen.   The core compiler
>>>>>>>>>>> includes all
>>>>>>>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>>>>>>>
>>>>>>>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>>>>>>>
>>>>>>>>> Actually, no, they are not.  Partial int modes can have bit sizes
>>>>>>>>> that
>>>>>>>>> are not power of two, and, if there isn't an int mode that is
>>>>>>>>> bigger, we'd
>>>>>>>>> want to round up the partial int bit size.  Something like ((2 *
>>>>>>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>>>>>>>> HOST_BITS_PER_WIDE_INT should do it.
>>>>>>>>>
>>>>>>>>>>>> I still would like to have the ability to provide
>>>>>>>>>>>> specializations of
>>>>>>>>>>>> wide_int
>>>>>>>>>>>> for "small" sizes, thus ideally wide_int would be a template
>>>>>>>>>>>> templated
>>>>>>>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should
>>>>>>>>>>>> be
>>>>>>>>>>>> identical to double_int, thus we should be able to do
>>>>>>>>>>>>
>>>>>>>>>>>> typedef wide_int<2> double_int;
>>>>>>>>>>>
>>>>>>>>>>> If you want to go down this path after the patches get in, go for
>>>>>>>>>>> it.
>>>>>>>>>>> I
>>>>>>>>>>> see no use at all for this.
>>>>>>>>>>> This was not meant to be a plug in replacement for double int.
>>>>>>>>>>> This
>>>>>>>>>>> goal of
>>>>>>>>>>> this patch is to get the compiler to do the constant math the way
>>>>>>>>>>> that
>>>>>>>>>>> the
>>>>>>>>>>> target does it.   Any such instantiation is by definition placing
>>>>>>>>>>> some
>>>>>>>>>>> predefined limit that some target may not want.
>>>>>>>>>>
>>>>>>>>>> Well, what I don't really like is that we now have two
>>>>>>>>>> implementations
>>>>>>>>>> of functions that perform integer math on two-HWI sized integers.
>>>>>>>>>> What
>>>>>>>>>> I also don't like too much is that we have two different
>>>>>>>>>> interfaces to
>>>>>>>>>> operate
>>>>>>>>>> on them!  Can't you see how I come to not liking this?  Especially
>>>>>>>>>> the
>>>>>>>>>> latter …
>>>>>>>>>
>>>>>>>>> double_int is logically dead.  Reactoring wide-int and double-int
>>>>>>>>> is a
>>>>>>>>> waste of time, as the time is better spent removing double-int from
>>>>>>>>> the
>>>>>>>>> compiler.  All the necessary semantics and code of double-int _has_
>>>>>>>>> been
>>>>>>>>> refactored into wide-int already.  Changing wide-int in any way to
>>>>>>>>> vend
>>>>>>>>> anything to double-int is wrong, as once double-int is removed,
>>>>>>>>> then all the
>>>>>>>>> api changes to make double-int share from wide-int is wasted and
>>>>>>>>> must then
>>>>>>>>> be removed.  The path forward is the complete removal of
>>>>>>>>> double-int; it is
>>>>>>>>> wrong, has been wrong and always will be wrong, nothing can change
>>>>>>>>> that.
>>>>>>>>
>>>>>>>> double_int, compared to wide_int, is fast and lean.  I doubt we will
>>>>>>>> get rid of it - you
>>>>>>>> will make compile-time math a _lot_ slower.  Just profile when you
>>>>>>>> for
>>>>>>>> example
>>>>>>>> change get_inner_reference to use wide_ints.
>>>>>>>>
>>>>>>>> To be able to remove double_int in favor of wide_int requires _at
>>>>>>>> least_
>>>>>>>> templating wide_int on 'len' and providing specializations for 1 and
>>>>>>>> 2.
>>>>>>>>
>>>>>>>> It might be a non-issue for math that operates on trees or RTXen due
>>>>>>>> to
>>>>>>>> the allocation overhead we pay, but in recent years we transitioned
>>>>>>>> important
>>>>>>>> paths away from using tree math to using double_ints _for speed
>>>>>>>> reasons_.
>>>>>>>>
>>>>>>>> Richard.
>>>>>>>
>>>>>>> i do not know why you believe this about the speed.     double int
>>>>>>> always
>>>>>>> does synthetic math since you do everything at 128 bit precision.
>>>>>>>
>>>>>>> the thing about wide int, is that since it does math to the
>>>>>>> precision's
>>>>>>> size, it almost never does uses synthetic operations since the sizes
>>>>>>> for
>>>>>>> almost every instance can be done using the native math on the
>>>>>>> machine.
>>>>>>> almost every call has a check to see if the operation can be done
>>>>>>> natively.
>>>>>>> I seriously doubt that you are going to do TI mode math much faster
>>>>>>> than i
>>>>>>> do it and if you do who cares.
>>>>>>>
>>>>>>> the number of calls does not effect the performance in any negative
>>>>>>> way and
>>>>>>> it fact is more efficient since common things that require more than
>>>>>>> one
>>>>>>> operation in double in are typically done in a single operation.
>>>>>>
>>>>>> Simple double-int operations like
>>>>>>
>>>>>> inline double_int
>>>>>> double_int::and_not (double_int b) const
>>>>>> {
>>>>>>    double_int result;
>>>>>>    result.low = low & ~b.low;
>>>>>>    result.high = high & ~b.high;
>>>>>>    return result;
>>>>>> }
>>>>>>
>>>>>> are always going to be faster than conditionally executing only one
>>>>>> operation
>>>>>> (but inside an offline function).
>>>>>
>>>>> OK, this is really in reply to the 4.8 thing, but it felt more
>>>>> appropriate here.
>>>>>
>>>>> It's interesting that you gave this example, since before you were
>>>>> complaining about too many fused ops.  Clearly this one could be
>>>>> removed in favour of separate and() and not() operations, but why
>>>>> not provide a fused one if there are clients who'll make use of it?
>>>>
>>>> I was more concerned about fused operations that use precision
>>>> or bitsize as input.  That is for example
>>>>
>>>>>> +  bool only_sign_bit_p (unsigned int prec) const;
>>>>>> +  bool only_sign_bit_p () const;
>>>>
>>>> The first is construct a wide-int with precision prec (and sign- or
>>>> zero-extend it) and then call only_sign_bit_p on it.  Such function
>>>> should not be necessary and existing callers should be questioned
>>>> instead of introducing it.
>>>>
>>>> In fact wide-int seems to have so many "fused" operations that
>>>> we run out of sensible recognizable names for them.  Which results
>>>> in a lot of confusion on what the functions actually do (at least for
>>>> me).
>>>
>>> Well, I suppose I can't really say anything useful either way on
>>> that one, since I'm not writing the patch and I'm not reviewing it :-)
>>>
>>>>> I think Kenny's API is just taking that to its logical conclusion.
>>>>> There doesn't seem to be anything sacrosanct about the current choice
>>>>> of what's fused and what isn't.
>>>>
>>>> Maybe.  I'd rather have seen an initial small wide-int API and fused
>>>> operations introduced separately together with the places they are
>>>> used.  In the current way it's way too tedious to go over all of them
>>>> and match them with callers, lookup enough context and then
>>>> make up my mind on whether the caller should do sth different or not.
>>>>
>>>> Thus, consider the big initial API a reason that all this review takes
>>>> so long ...
>>>>
>>>>> The speed problem we had using trees for internal arithmetic isn't
>>>>> IMO a good argument for keeping double_int in preference to wide_int.
>>>>> Allocating and constructing tree objects to hold temporary values,
>>>>> storing an integer representation in it, then calling tree arithmetic
>>>>> routines that pull out the integer representation again and create a
>>>>> tree to hold the result, is going to be much slower than using either
>>>>> double_int or wide_int.  I'd be very surprised if we notice any
>>>>> measurable difference between double_int and wide_int here.
>>>>>
>>>>> I still see no reason to keep double_int around.  The width of a host
>>>>> wide integer really shouldn't have any significance.
>>>>>
>>>>> Your main complaint seems to be that the wide_int API is different
>>>>> from the double_int one, but we can't literally use the same API, since
>>>>> double_int has an implicit precision and bitsize, and wide_int doesn't.
>>>>> Having a precision that is separate from the underlying representation
>>>>> is IMO the most important feature of wide_int, so:
>>>>>
>>>>>     template wide_int<2> double_int;
>>>>>
>>>>> is never going to be a drop-in, API-compatible replacement for
>>>>> double_int.
>>>>
>>>> My reasoning was that if you strip wide-int of precision and bitsize
>>>> you have a double_int<N> class.
>>>
>>> But you don't!  Because...
>>>
>>>> Thus wide-int should have a base
>>>> of that kind and just add precision / bitsize ontop of that.  It
>>>> wouldn't
>>>> be a step forward if we end up replacing double_int uses with
>>>> wide_int uses with precision of 2 * HOST_BITS_PER_WIDE_INT,
>>>> would it?
>>>
>>> ...the precision and bitsize isn't an optional extra, either conceptually
>>> or in implementation.  wide_int happens to use N HOST_WIDE_INTS under
>>> the hood, but the value of N is an internal implementation detail.
>>> No operations are done to N HWIs, they're done to the number of bits
>>> in the operands.  Whereas a double_int<N> class does everything to N
>>> HWIs.
>>
>> If that's the only effect then either bitsize or precision is redundant
>> (and
>> we also have len ...).  Note I did not mention len above, thus the base
>> class would retain 'len' and double-int would simply use 2 for it
>> (if you don't template it but make it variable).
>>
>> Richard.
>>
> NO, in your own words, there are two parts of the compiler that want the
> infinite model.   The rest wants to do the math the way the target does it.
> My version now accommodates both.    In tree vrp it scans the gimple and
> determines what the largest type is and that is the basis of all of the math
> in this pass.  If you just make double int bigger, then you are paying for
> big math everywhere.

You have an artificial limit on what 'len' can be.  And you do not accomodate
users that do not want to pay the storage penalty for that arbitrary upper limit
choice.  That's all because 'len' may grow (mutate).  You could alternatively
not allow bitsize to grow / mutate and have allocation tied to bitsize instead
of len.

Ideally the wide-int interface would have two storage models:

class alloc_storage
{
  unsigned len; /* or bitsize */
  HOST_WIDE_INT *hwis;

  HOST_WIDE_INT& operator[](unsigned i) { return hwis[i]; }
}

class max_mode
{
  HOST_WIDE_INT hwis[largest integer mode size in hwi];

  HOST_WIDE_INT& operator[](unsigned i) { return hwis[i]; }
}

template <class storage>
class wide_int : storage
{

so you can even re-use the (const) in-place storage of INTEGER_CSTs
or RTL CONST_WIDEs.  And VRP would simply have its own storage
supporting 2 times the largest integer mode (or whatever choice it has).
And double-int would simply embed two.

Maybe this is the perfect example for introducing virtual functions as well
to ease inter-operability between the wide-int variants without making each
member a template on the 2nd wide-int operand (it's of course auto-deduced,
but well ...).

The above is just a brain-dump, details may need further thinking
Like the operator[], maybe the storage model should just be able
to return a pointer to the array of HWIs, this way the actual workers
can be out-of-line and non-templates.

Richard.

>
>>> Richard
>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 14:07                                                                   ` Richard Biener
@ 2012-10-31 14:25                                                                     ` Kenneth Zadeck
  2012-10-31 14:25                                                                       ` Richard Biener
  2012-10-31 20:07                                                                     ` patch to fix constant math - 4th patch - the wide-int class Mike Stump
  1 sibling, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-31 14:25 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford


On 10/31/2012 10:05 AM, Richard Biener wrote:
> On Wed, Oct 31, 2012 at 2:54 PM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> On 10/31/2012 08:11 AM, Richard Biener wrote:
>>> On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford
>>> <rdsandiford@googlemail.com> wrote:
>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>> On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford
>>>>> <rdsandiford@googlemail.com> wrote:
>>>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>>> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>>>>>>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump <mikestump@comcast.net>
>>>>>>>>> wrote:
>>>>>>>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener
>>>>>>>>>> <richard.guenther@gmail.com>
>>>>>>>>>> wrote:
>>>>>>>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>>>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>>>>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>>>>>>>>
>>>>>>>>>>>>> are we sure this rounds properly?  Consider a port with max byte
>>>>>>>>>>>>> mode
>>>>>>>>>>>>> size 4 on a 64bit host.
>>>>>>>>>>>> I do not believe that this can happen.   The core compiler
>>>>>>>>>>>> includes all
>>>>>>>>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>>>>>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>>>>>>>> Actually, no, they are not.  Partial int modes can have bit sizes
>>>>>>>>>> that
>>>>>>>>>> are not power of two, and, if there isn't an int mode that is
>>>>>>>>>> bigger, we'd
>>>>>>>>>> want to round up the partial int bit size.  Something like ((2 *
>>>>>>>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>>>>>>>>> HOST_BITS_PER_WIDE_INT should do it.
>>>>>>>>>>
>>>>>>>>>>>>> I still would like to have the ability to provide
>>>>>>>>>>>>> specializations of
>>>>>>>>>>>>> wide_int
>>>>>>>>>>>>> for "small" sizes, thus ideally wide_int would be a template
>>>>>>>>>>>>> templated
>>>>>>>>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should
>>>>>>>>>>>>> be
>>>>>>>>>>>>> identical to double_int, thus we should be able to do
>>>>>>>>>>>>>
>>>>>>>>>>>>> typedef wide_int<2> double_int;
>>>>>>>>>>>> If you want to go down this path after the patches get in, go for
>>>>>>>>>>>> it.
>>>>>>>>>>>> I
>>>>>>>>>>>> see no use at all for this.
>>>>>>>>>>>> This was not meant to be a plug in replacement for double int.
>>>>>>>>>>>> This
>>>>>>>>>>>> goal of
>>>>>>>>>>>> this patch is to get the compiler to do the constant math the way
>>>>>>>>>>>> that
>>>>>>>>>>>> the
>>>>>>>>>>>> target does it.   Any such instantiation is by definition placing
>>>>>>>>>>>> some
>>>>>>>>>>>> predefined limit that some target may not want.
>>>>>>>>>>> Well, what I don't really like is that we now have two
>>>>>>>>>>> implementations
>>>>>>>>>>> of functions that perform integer math on two-HWI sized integers.
>>>>>>>>>>> What
>>>>>>>>>>> I also don't like too much is that we have two different
>>>>>>>>>>> interfaces to
>>>>>>>>>>> operate
>>>>>>>>>>> on them!  Can't you see how I come to not liking this?  Especially
>>>>>>>>>>> the
>>>>>>>>>>> latter Â…
>>>>>>>>>> double_int is logically dead.  Reactoring wide-int and double-int
>>>>>>>>>> is a
>>>>>>>>>> waste of time, as the time is better spent removing double-int from
>>>>>>>>>> the
>>>>>>>>>> compiler.  All the necessary semantics and code of double-int _has_
>>>>>>>>>> been
>>>>>>>>>> refactored into wide-int already.  Changing wide-int in any way to
>>>>>>>>>> vend
>>>>>>>>>> anything to double-int is wrong, as once double-int is removed,
>>>>>>>>>> then all the
>>>>>>>>>> api changes to make double-int share from wide-int is wasted and
>>>>>>>>>> must then
>>>>>>>>>> be removed.  The path forward is the complete removal of
>>>>>>>>>> double-int; it is
>>>>>>>>>> wrong, has been wrong and always will be wrong, nothing can change
>>>>>>>>>> that.
>>>>>>>>> double_int, compared to wide_int, is fast and lean.  I doubt we will
>>>>>>>>> get rid of it - you
>>>>>>>>> will make compile-time math a _lot_ slower.  Just profile when you
>>>>>>>>> for
>>>>>>>>> example
>>>>>>>>> change get_inner_reference to use wide_ints.
>>>>>>>>>
>>>>>>>>> To be able to remove double_int in favor of wide_int requires _at
>>>>>>>>> least_
>>>>>>>>> templating wide_int on 'len' and providing specializations for 1 and
>>>>>>>>> 2.
>>>>>>>>>
>>>>>>>>> It might be a non-issue for math that operates on trees or RTXen due
>>>>>>>>> to
>>>>>>>>> the allocation overhead we pay, but in recent years we transitioned
>>>>>>>>> important
>>>>>>>>> paths away from using tree math to using double_ints _for speed
>>>>>>>>> reasons_.
>>>>>>>>>
>>>>>>>>> Richard.
>>>>>>>> i do not know why you believe this about the speed.     double int
>>>>>>>> always
>>>>>>>> does synthetic math since you do everything at 128 bit precision.
>>>>>>>>
>>>>>>>> the thing about wide int, is that since it does math to the
>>>>>>>> precision's
>>>>>>>> size, it almost never does uses synthetic operations since the sizes
>>>>>>>> for
>>>>>>>> almost every instance can be done using the native math on the
>>>>>>>> machine.
>>>>>>>> almost every call has a check to see if the operation can be done
>>>>>>>> natively.
>>>>>>>> I seriously doubt that you are going to do TI mode math much faster
>>>>>>>> than i
>>>>>>>> do it and if you do who cares.
>>>>>>>>
>>>>>>>> the number of calls does not effect the performance in any negative
>>>>>>>> way and
>>>>>>>> it fact is more efficient since common things that require more than
>>>>>>>> one
>>>>>>>> operation in double in are typically done in a single operation.
>>>>>>> Simple double-int operations like
>>>>>>>
>>>>>>> inline double_int
>>>>>>> double_int::and_not (double_int b) const
>>>>>>> {
>>>>>>>     double_int result;
>>>>>>>     result.low = low & ~b.low;
>>>>>>>     result.high = high & ~b.high;
>>>>>>>     return result;
>>>>>>> }
>>>>>>>
>>>>>>> are always going to be faster than conditionally executing only one
>>>>>>> operation
>>>>>>> (but inside an offline function).
>>>>>> OK, this is really in reply to the 4.8 thing, but it felt more
>>>>>> appropriate here.
>>>>>>
>>>>>> It's interesting that you gave this example, since before you were
>>>>>> complaining about too many fused ops.  Clearly this one could be
>>>>>> removed in favour of separate and() and not() operations, but why
>>>>>> not provide a fused one if there are clients who'll make use of it?
>>>>> I was more concerned about fused operations that use precision
>>>>> or bitsize as input.  That is for example
>>>>>
>>>>>>> +  bool only_sign_bit_p (unsigned int prec) const;
>>>>>>> +  bool only_sign_bit_p () const;
>>>>> The first is construct a wide-int with precision prec (and sign- or
>>>>> zero-extend it) and then call only_sign_bit_p on it.  Such function
>>>>> should not be necessary and existing callers should be questioned
>>>>> instead of introducing it.
>>>>>
>>>>> In fact wide-int seems to have so many "fused" operations that
>>>>> we run out of sensible recognizable names for them.  Which results
>>>>> in a lot of confusion on what the functions actually do (at least for
>>>>> me).
>>>> Well, I suppose I can't really say anything useful either way on
>>>> that one, since I'm not writing the patch and I'm not reviewing it :-)
>>>>
>>>>>> I think Kenny's API is just taking that to its logical conclusion.
>>>>>> There doesn't seem to be anything sacrosanct about the current choice
>>>>>> of what's fused and what isn't.
>>>>> Maybe.  I'd rather have seen an initial small wide-int API and fused
>>>>> operations introduced separately together with the places they are
>>>>> used.  In the current way it's way too tedious to go over all of them
>>>>> and match them with callers, lookup enough context and then
>>>>> make up my mind on whether the caller should do sth different or not.
>>>>>
>>>>> Thus, consider the big initial API a reason that all this review takes
>>>>> so long ...
>>>>>
>>>>>> The speed problem we had using trees for internal arithmetic isn't
>>>>>> IMO a good argument for keeping double_int in preference to wide_int.
>>>>>> Allocating and constructing tree objects to hold temporary values,
>>>>>> storing an integer representation in it, then calling tree arithmetic
>>>>>> routines that pull out the integer representation again and create a
>>>>>> tree to hold the result, is going to be much slower than using either
>>>>>> double_int or wide_int.  I'd be very surprised if we notice any
>>>>>> measurable difference between double_int and wide_int here.
>>>>>>
>>>>>> I still see no reason to keep double_int around.  The width of a host
>>>>>> wide integer really shouldn't have any significance.
>>>>>>
>>>>>> Your main complaint seems to be that the wide_int API is different
>>>>>> from the double_int one, but we can't literally use the same API, since
>>>>>> double_int has an implicit precision and bitsize, and wide_int doesn't.
>>>>>> Having a precision that is separate from the underlying representation
>>>>>> is IMO the most important feature of wide_int, so:
>>>>>>
>>>>>>      template wide_int<2> double_int;
>>>>>>
>>>>>> is never going to be a drop-in, API-compatible replacement for
>>>>>> double_int.
>>>>> My reasoning was that if you strip wide-int of precision and bitsize
>>>>> you have a double_int<N> class.
>>>> But you don't!  Because...
>>>>
>>>>> Thus wide-int should have a base
>>>>> of that kind and just add precision / bitsize ontop of that.  It
>>>>> wouldn't
>>>>> be a step forward if we end up replacing double_int uses with
>>>>> wide_int uses with precision of 2 * HOST_BITS_PER_WIDE_INT,
>>>>> would it?
>>>> ...the precision and bitsize isn't an optional extra, either conceptually
>>>> or in implementation.  wide_int happens to use N HOST_WIDE_INTS under
>>>> the hood, but the value of N is an internal implementation detail.
>>>> No operations are done to N HWIs, they're done to the number of bits
>>>> in the operands.  Whereas a double_int<N> class does everything to N
>>>> HWIs.
>>> If that's the only effect then either bitsize or precision is redundant
>>> (and
>>> we also have len ...).  Note I did not mention len above, thus the base
>>> class would retain 'len' and double-int would simply use 2 for it
>>> (if you don't template it but make it variable).
>>>
>>> Richard.
>>>
>> NO, in your own words, there are two parts of the compiler that want the
>> infinite model.   The rest wants to do the math the way the target does it.
>> My version now accommodates both.    In tree vrp it scans the gimple and
>> determines what the largest type is and that is the basis of all of the math
>> in this pass.  If you just make double int bigger, then you are paying for
>> big math everywhere.
> You have an artificial limit on what 'len' can be.  And you do not accomodate
> users that do not want to pay the storage penalty for that arbitrary upper limit
> choice.  That's all because 'len' may grow (mutate).  You could alternatively
> not allow bitsize to grow / mutate and have allocation tied to bitsize instead
> of len.
It is not artificial, it is based on the target.  I chose to do it that 
way because i "knew" that having a fixed size would be faster than doing 
an alloca on for every wide-int.    If we feel that it is important to 
be able to do truly arbitrary infinite precision arithmetic (as opposed 
to just some fixed amount larger than the size of the type) then we can 
have a subclass that does this. However, there is not a need to do this 
in the compiler currently and so using this as an argument against 
wide-int is really not fair.

However, as the machines allow wider math, your really do not want to 
penalize every program that is compiled with this burden.   It was ok 
for double int to do so, but when machines commonly have oi mode, it 
will still be the case that more than 99% of the variables will be 64 
bits or less.

I do worry a lot about adding layers like this on the efficiency of the 
compiler.   you made a valid point that a lot of the double int routines 
could be done inline and my plan is take the parts of the functions that 
notice that the precision fits in a hwi and do them inline.

If your proposed solution causes a function call to access the elements, 
then we are doomed.
> Ideally the wide-int interface would have two storage models:
>
> class alloc_storage
> {
>    unsigned len; /* or bitsize */
>    HOST_WIDE_INT *hwis;
>
>    HOST_WIDE_INT& operator[](unsigned i) { return hwis[i]; }
> }
>
> class max_mode
> {
>    HOST_WIDE_INT hwis[largest integer mode size in hwi];
>
>    HOST_WIDE_INT& operator[](unsigned i) { return hwis[i]; }
> }
>
> template <class storage>
> class wide_int : storage
> {
>
> so you can even re-use the (const) in-place storage of INTEGER_CSTs
> or RTL CONST_WIDEs.  And VRP would simply have its own storage
> supporting 2 times the largest integer mode (or whatever choice it has).
> And double-int would simply embed two.
>
> Maybe this is the perfect example for introducing virtual functions as well
> to ease inter-operability between the wide-int variants without making each
> member a template on the 2nd wide-int operand (it's of course auto-deduced,
> but well ...).
>
> The above is just a brain-dump, details may need further thinking
> Like the operator[], maybe the storage model should just be able
> to return a pointer to the array of HWIs, this way the actual workers
> can be out-of-line and non-templates.
>
> Richard.
>
>>>> Richard
>>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 14:25                                                                     ` Kenneth Zadeck
@ 2012-10-31 14:25                                                                       ` Richard Biener
  2012-10-31 14:30                                                                         ` Kenneth Zadeck
                                                                                           ` (3 more replies)
  0 siblings, 4 replies; 217+ messages in thread
From: Richard Biener @ 2012-10-31 14:25 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford

On Wed, Oct 31, 2012 at 3:18 PM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
>
> On 10/31/2012 10:05 AM, Richard Biener wrote:
>>
>> On Wed, Oct 31, 2012 at 2:54 PM, Kenneth Zadeck
>> <zadeck@naturalbridge.com> wrote:
>>>
>>> On 10/31/2012 08:11 AM, Richard Biener wrote:
>>>>
>>>> On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford
>>>> <rdsandiford@googlemail.com> wrote:
>>>>>
>>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>>
>>>>>> On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford
>>>>>> <rdsandiford@googlemail.com> wrote:
>>>>>>>
>>>>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>>>>
>>>>>>>> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>
>>>>>>>>> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>>>>>>>>>
>>>>>>>>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump
>>>>>>>>>> <mikestump@comcast.net>
>>>>>>>>>> wrote:
>>>>>>>>>>>
>>>>>>>>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener
>>>>>>>>>>> <richard.guenther@gmail.com>
>>>>>>>>>>> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>>>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>>>>>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> are we sure this rounds properly?  Consider a port with max
>>>>>>>>>>>>>> byte
>>>>>>>>>>>>>> mode
>>>>>>>>>>>>>> size 4 on a 64bit host.
>>>>>>>>>>>>>
>>>>>>>>>>>>> I do not believe that this can happen.   The core compiler
>>>>>>>>>>>>> includes all
>>>>>>>>>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>>>>>>>>>
>>>>>>>>>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>>>>>>>>>
>>>>>>>>>>> Actually, no, they are not.  Partial int modes can have bit sizes
>>>>>>>>>>> that
>>>>>>>>>>> are not power of two, and, if there isn't an int mode that is
>>>>>>>>>>> bigger, we'd
>>>>>>>>>>> want to round up the partial int bit size.  Something like ((2 *
>>>>>>>>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>>>>>>>>>> HOST_BITS_PER_WIDE_INT should do it.
>>>>>>>>>>>
>>>>>>>>>>>>>> I still would like to have the ability to provide
>>>>>>>>>>>>>> specializations of
>>>>>>>>>>>>>> wide_int
>>>>>>>>>>>>>> for "small" sizes, thus ideally wide_int would be a template
>>>>>>>>>>>>>> templated
>>>>>>>>>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2>
>>>>>>>>>>>>>> should
>>>>>>>>>>>>>> be
>>>>>>>>>>>>>> identical to double_int, thus we should be able to do
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> typedef wide_int<2> double_int;
>>>>>>>>>>>>>
>>>>>>>>>>>>> If you want to go down this path after the patches get in, go
>>>>>>>>>>>>> for
>>>>>>>>>>>>> it.
>>>>>>>>>>>>> I
>>>>>>>>>>>>> see no use at all for this.
>>>>>>>>>>>>> This was not meant to be a plug in replacement for double int.
>>>>>>>>>>>>> This
>>>>>>>>>>>>> goal of
>>>>>>>>>>>>> this patch is to get the compiler to do the constant math the
>>>>>>>>>>>>> way
>>>>>>>>>>>>> that
>>>>>>>>>>>>> the
>>>>>>>>>>>>> target does it.   Any such instantiation is by definition
>>>>>>>>>>>>> placing
>>>>>>>>>>>>> some
>>>>>>>>>>>>> predefined limit that some target may not want.
>>>>>>>>>>>>
>>>>>>>>>>>> Well, what I don't really like is that we now have two
>>>>>>>>>>>> implementations
>>>>>>>>>>>> of functions that perform integer math on two-HWI sized
>>>>>>>>>>>> integers.
>>>>>>>>>>>> What
>>>>>>>>>>>> I also don't like too much is that we have two different
>>>>>>>>>>>> interfaces to
>>>>>>>>>>>> operate
>>>>>>>>>>>> on them!  Can't you see how I come to not liking this?
>>>>>>>>>>>> Especially
>>>>>>>>>>>> the
>>>>>>>>>>>> latter …
>>>>>>>>>>>
>>>>>>>>>>> double_int is logically dead.  Reactoring wide-int and double-int
>>>>>>>>>>> is a
>>>>>>>>>>> waste of time, as the time is better spent removing double-int
>>>>>>>>>>> from
>>>>>>>>>>> the
>>>>>>>>>>> compiler.  All the necessary semantics and code of double-int
>>>>>>>>>>> _has_
>>>>>>>>>>> been
>>>>>>>>>>> refactored into wide-int already.  Changing wide-int in any way
>>>>>>>>>>> to
>>>>>>>>>>> vend
>>>>>>>>>>> anything to double-int is wrong, as once double-int is removed,
>>>>>>>>>>> then all the
>>>>>>>>>>> api changes to make double-int share from wide-int is wasted and
>>>>>>>>>>> must then
>>>>>>>>>>> be removed.  The path forward is the complete removal of
>>>>>>>>>>> double-int; it is
>>>>>>>>>>> wrong, has been wrong and always will be wrong, nothing can
>>>>>>>>>>> change
>>>>>>>>>>> that.
>>>>>>>>>>
>>>>>>>>>> double_int, compared to wide_int, is fast and lean.  I doubt we
>>>>>>>>>> will
>>>>>>>>>> get rid of it - you
>>>>>>>>>> will make compile-time math a _lot_ slower.  Just profile when you
>>>>>>>>>> for
>>>>>>>>>> example
>>>>>>>>>> change get_inner_reference to use wide_ints.
>>>>>>>>>>
>>>>>>>>>> To be able to remove double_int in favor of wide_int requires _at
>>>>>>>>>> least_
>>>>>>>>>> templating wide_int on 'len' and providing specializations for 1
>>>>>>>>>> and
>>>>>>>>>> 2.
>>>>>>>>>>
>>>>>>>>>> It might be a non-issue for math that operates on trees or RTXen
>>>>>>>>>> due
>>>>>>>>>> to
>>>>>>>>>> the allocation overhead we pay, but in recent years we
>>>>>>>>>> transitioned
>>>>>>>>>> important
>>>>>>>>>> paths away from using tree math to using double_ints _for speed
>>>>>>>>>> reasons_.
>>>>>>>>>>
>>>>>>>>>> Richard.
>>>>>>>>>
>>>>>>>>> i do not know why you believe this about the speed.     double int
>>>>>>>>> always
>>>>>>>>> does synthetic math since you do everything at 128 bit precision.
>>>>>>>>>
>>>>>>>>> the thing about wide int, is that since it does math to the
>>>>>>>>> precision's
>>>>>>>>> size, it almost never does uses synthetic operations since the
>>>>>>>>> sizes
>>>>>>>>> for
>>>>>>>>> almost every instance can be done using the native math on the
>>>>>>>>> machine.
>>>>>>>>> almost every call has a check to see if the operation can be done
>>>>>>>>> natively.
>>>>>>>>> I seriously doubt that you are going to do TI mode math much faster
>>>>>>>>> than i
>>>>>>>>> do it and if you do who cares.
>>>>>>>>>
>>>>>>>>> the number of calls does not effect the performance in any negative
>>>>>>>>> way and
>>>>>>>>> it fact is more efficient since common things that require more
>>>>>>>>> than
>>>>>>>>> one
>>>>>>>>> operation in double in are typically done in a single operation.
>>>>>>>>
>>>>>>>> Simple double-int operations like
>>>>>>>>
>>>>>>>> inline double_int
>>>>>>>> double_int::and_not (double_int b) const
>>>>>>>> {
>>>>>>>>     double_int result;
>>>>>>>>     result.low = low & ~b.low;
>>>>>>>>     result.high = high & ~b.high;
>>>>>>>>     return result;
>>>>>>>> }
>>>>>>>>
>>>>>>>> are always going to be faster than conditionally executing only one
>>>>>>>> operation
>>>>>>>> (but inside an offline function).
>>>>>>>
>>>>>>> OK, this is really in reply to the 4.8 thing, but it felt more
>>>>>>> appropriate here.
>>>>>>>
>>>>>>> It's interesting that you gave this example, since before you were
>>>>>>> complaining about too many fused ops.  Clearly this one could be
>>>>>>> removed in favour of separate and() and not() operations, but why
>>>>>>> not provide a fused one if there are clients who'll make use of it?
>>>>>>
>>>>>> I was more concerned about fused operations that use precision
>>>>>> or bitsize as input.  That is for example
>>>>>>
>>>>>>>> +  bool only_sign_bit_p (unsigned int prec) const;
>>>>>>>> +  bool only_sign_bit_p () const;
>>>>>>
>>>>>> The first is construct a wide-int with precision prec (and sign- or
>>>>>> zero-extend it) and then call only_sign_bit_p on it.  Such function
>>>>>> should not be necessary and existing callers should be questioned
>>>>>> instead of introducing it.
>>>>>>
>>>>>> In fact wide-int seems to have so many "fused" operations that
>>>>>> we run out of sensible recognizable names for them.  Which results
>>>>>> in a lot of confusion on what the functions actually do (at least for
>>>>>> me).
>>>>>
>>>>> Well, I suppose I can't really say anything useful either way on
>>>>> that one, since I'm not writing the patch and I'm not reviewing it :-)
>>>>>
>>>>>>> I think Kenny's API is just taking that to its logical conclusion.
>>>>>>> There doesn't seem to be anything sacrosanct about the current choice
>>>>>>> of what's fused and what isn't.
>>>>>>
>>>>>> Maybe.  I'd rather have seen an initial small wide-int API and fused
>>>>>> operations introduced separately together with the places they are
>>>>>> used.  In the current way it's way too tedious to go over all of them
>>>>>> and match them with callers, lookup enough context and then
>>>>>> make up my mind on whether the caller should do sth different or not.
>>>>>>
>>>>>> Thus, consider the big initial API a reason that all this review takes
>>>>>> so long ...
>>>>>>
>>>>>>> The speed problem we had using trees for internal arithmetic isn't
>>>>>>> IMO a good argument for keeping double_int in preference to wide_int.
>>>>>>> Allocating and constructing tree objects to hold temporary values,
>>>>>>> storing an integer representation in it, then calling tree arithmetic
>>>>>>> routines that pull out the integer representation again and create a
>>>>>>> tree to hold the result, is going to be much slower than using either
>>>>>>> double_int or wide_int.  I'd be very surprised if we notice any
>>>>>>> measurable difference between double_int and wide_int here.
>>>>>>>
>>>>>>> I still see no reason to keep double_int around.  The width of a host
>>>>>>> wide integer really shouldn't have any significance.
>>>>>>>
>>>>>>> Your main complaint seems to be that the wide_int API is different
>>>>>>> from the double_int one, but we can't literally use the same API,
>>>>>>> since
>>>>>>> double_int has an implicit precision and bitsize, and wide_int
>>>>>>> doesn't.
>>>>>>> Having a precision that is separate from the underlying
>>>>>>> representation
>>>>>>> is IMO the most important feature of wide_int, so:
>>>>>>>
>>>>>>>      template wide_int<2> double_int;
>>>>>>>
>>>>>>> is never going to be a drop-in, API-compatible replacement for
>>>>>>> double_int.
>>>>>>
>>>>>> My reasoning was that if you strip wide-int of precision and bitsize
>>>>>> you have a double_int<N> class.
>>>>>
>>>>> But you don't!  Because...
>>>>>
>>>>>> Thus wide-int should have a base
>>>>>> of that kind and just add precision / bitsize ontop of that.  It
>>>>>> wouldn't
>>>>>> be a step forward if we end up replacing double_int uses with
>>>>>> wide_int uses with precision of 2 * HOST_BITS_PER_WIDE_INT,
>>>>>> would it?
>>>>>
>>>>> ...the precision and bitsize isn't an optional extra, either
>>>>> conceptually
>>>>> or in implementation.  wide_int happens to use N HOST_WIDE_INTS under
>>>>> the hood, but the value of N is an internal implementation detail.
>>>>> No operations are done to N HWIs, they're done to the number of bits
>>>>> in the operands.  Whereas a double_int<N> class does everything to N
>>>>> HWIs.
>>>>
>>>> If that's the only effect then either bitsize or precision is redundant
>>>> (and
>>>> we also have len ...).  Note I did not mention len above, thus the base
>>>> class would retain 'len' and double-int would simply use 2 for it
>>>> (if you don't template it but make it variable).
>>>>
>>>> Richard.
>>>>
>>> NO, in your own words, there are two parts of the compiler that want the
>>> infinite model.   The rest wants to do the math the way the target does
>>> it.
>>> My version now accommodates both.    In tree vrp it scans the gimple and
>>> determines what the largest type is and that is the basis of all of the
>>> math
>>> in this pass.  If you just make double int bigger, then you are paying
>>> for
>>> big math everywhere.
>>
>> You have an artificial limit on what 'len' can be.  And you do not
>> accomodate
>> users that do not want to pay the storage penalty for that arbitrary upper
>> limit
>> choice.  That's all because 'len' may grow (mutate).  You could
>> alternatively
>> not allow bitsize to grow / mutate and have allocation tied to bitsize
>> instead
>> of len.
>
> It is not artificial, it is based on the target.  I chose to do it that way
> because i "knew" that having a fixed size would be faster than doing an
> alloca on for every wide-int.    If we feel that it is important to be able
> to do truly arbitrary infinite precision arithmetic (as opposed to just some
> fixed amount larger than the size of the type) then we can have a subclass
> that does this. However, there is not a need to do this in the compiler
> currently and so using this as an argument against wide-int is really not
> fair.

Well, it is artifical as you had to increase it by a factor of two to handle
the use in VRP.  It is also "artificial" as it wastes storage.

> However, as the machines allow wider math, your really do not want to
> penalize every program that is compiled with this burden.   It was ok for
> double int to do so, but when machines commonly have oi mode, it will still
> be the case that more than 99% of the variables will be 64 bits or less.
>
> I do worry a lot about adding layers like this on the efficiency of the
> compiler.   you made a valid point that a lot of the double int routines
> could be done inline and my plan is take the parts of the functions that
> notice that the precision fits in a hwi and do them inline.
>
> If your proposed solution causes a function call to access the elements,
> then we are doomed.

Well, if it causes a function call to access a pointer to the array of elements
which you can cache then it wouldn't be that bad.  And with templates
we can inline the access anyway.

Richard.

>> Ideally the wide-int interface would have two storage models:
>>
>> class alloc_storage
>> {
>>    unsigned len; /* or bitsize */
>>    HOST_WIDE_INT *hwis;
>>
>>    HOST_WIDE_INT& operator[](unsigned i) { return hwis[i]; }
>> }
>>
>> class max_mode
>> {
>>    HOST_WIDE_INT hwis[largest integer mode size in hwi];
>>
>>    HOST_WIDE_INT& operator[](unsigned i) { return hwis[i]; }
>> }
>>
>> template <class storage>
>> class wide_int : storage
>> {
>>
>> so you can even re-use the (const) in-place storage of INTEGER_CSTs
>> or RTL CONST_WIDEs.  And VRP would simply have its own storage
>> supporting 2 times the largest integer mode (or whatever choice it has).
>> And double-int would simply embed two.
>>
>> Maybe this is the perfect example for introducing virtual functions as
>> well
>> to ease inter-operability between the wide-int variants without making
>> each
>> member a template on the 2nd wide-int operand (it's of course
>> auto-deduced,
>> but well ...).
>>
>> The above is just a brain-dump, details may need further thinking
>> Like the operator[], maybe the storage model should just be able
>> to return a pointer to the array of HWIs, this way the actual workers
>> can be out-of-line and non-templates.
>>
>> Richard.
>>
>>>>> Richard
>>>
>>>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 13:56                                                                       ` Richard Biener
@ 2012-10-31 14:26                                                                         ` Kenneth Zadeck
  2012-10-31 19:45                                                                         ` Mike Stump
  1 sibling, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-31 14:26 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford


On 10/31/2012 09:54 AM, Richard Biener wrote:
> On Wed, Oct 31, 2012 at 2:30 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>>> But that means that wide_int has to model a P-bit operation as a
>>>> "normal" len*HOST_WIDE_INT operation and then fix up the result
>>>> after the fact, which seems unnecessarily convoluted.
>>> It does that right now.  The operations are carried out in a loop
>>> over len HOST_WIDE_INT parts, the last HWI is then special-treated
>>> to account for precision/size.  (yes, 'len' is also used as optimization - the
>>> fact that len ends up being mutable is another thing I dislike about
>>> wide-int.  If wide-ints are cheap then all ops should be non-mutating
>>> (at least to 'len')).
>> But the point of having a mutating len is that things like zero and -1
>> are common even for OImode values.  So if you're doing someting potentially
>> expensive like OImode multiplication, why do it to the number of
>> HOST_WIDE_INTs needed for an OImode value when the value we're
>> processing has only one significant HOST_WIDE_INT?
> I don't propose doing that.  I propose that no wide-int member function
> may _change_ it's len (to something larger).  Only that way you can
> avoid allocating wasted space for zero and -1.  That way also the
> artificial limit on 2 * largest-int-mode-hwis goes.
it is now 4x not 2x to accomodate the extra bit in tree-vrp.

remember that the space burden is minimal.    wide-ints are not 
persistent and there are never more than a handful at a time.

>>>>   I still don't
>>>> see why a full-precision 2*HOST_WIDE_INT operation (or a full-precision
>>>> X*HOST_WIDE_INT operation for any X) has any special meaning.
>>> Well, the same reason as a HOST_WIDE_INT variable has a meaning.
>>> We use it to constrain what we (efficiently) want to work on.  For example
>>> CCP might iterate up to 2 * HOST_BITS_PER_WIDE_INT times when
>>> doing bit-constant-propagation in loops (for TImode integers on a x86_64 host).
>> But what about targets with modes wider than TImode?  Would double_int
>> still be appropriate then?  If not, why does CCP have to use a templated
>> type with a fixed number of HWIs (and all arithmetic done to a fixed
>> number of HWIs) rather than one that can adapt to the runtime values,
>> like wide_int can?
> Because nobody cares about accurate bit-tracking for modes larger than
> TImode.  And because no convenient abstraction was available ;)
yes, but tree-vrp does not even work for timode.  and there are not 
tests to scale it back when it does see ti-mode.   I understand that 
these can be added, but they so far have not been.

I would also point out that i was corrected on this point by (i believe) 
lawrence.   He points out that tree-vrp is still important for 
converting signed to unsigned for larger modes.


>>> Oh, and I don't necessary see a use of double_int in its current form
>>> but for an integer representation on the host that is efficient to manipulate
>>> integer constants of a target dependent size.  For example the target
>>> detail that we have partial integer modes with bitsize > precision and that
>>> the bits > precision appearantly have a meaning when looking at the
>>> bit-representation of a constant should not be part of the base class
>>> of wide-int (I doubt it belongs to wide-int at all, but I guess you know more
>>> about the reason we track bitsize in addition to precision - I think it's
>>> abstraction at the wrong level, the tree level does fine without knowing
>>> about bitsize).
>> TBH I'm uneasy about the bitsize thing too.  I think bitsize is only
>> tracked for shift truncation, and if so, I agree it makes sense
>> to do that separately.
> So, can we please remove all traces of bitsize from wide-int then?
>
>> But anyway, this whole discussion seems to have reached a stalemate.
>> Or I suppose a de-facto rejection, since you're the only person in
>> a position to approve the thing :-)
> There are many (silent) people that are able to approve the thing.  But the
> point is I have too many issues with the current patch that I'm unable
> to point at a specific thing I want Kenny to change after which the patch
> would be fine.  So I rely on some guesswork from Kenny giving my
> advices "leaner API", "less fused ops", "get rid of bitsize", "think of
> abstracting the core HWI[len] operation", "there should be no tree or
> RTL dependencies in the wide-int API" to produce an updated variant.
> Which of course takes time, which of course crosses my vacation, which
> in the end means it isn't going to make 4.8 (I _do_ like the idea of not
> having a dependence on host properties for integer constant representation).
>
> Btw, a good hint at what a minimal wide-int API would look like is if
> you _just_ replace double-int users with it.  Then you obviously have to
> implement only the double-int interface and conversion from/to double-int.
>
> Richard.
>
>
>> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 14:25                                                                       ` Richard Biener
@ 2012-10-31 14:30                                                                         ` Kenneth Zadeck
  2012-11-01 22:13                                                                         ` patch to fix constant math - 8th patch - tree-vrp.c Kenneth Zadeck
                                                                                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-31 14:30 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford


On 10/31/2012 10:24 AM, Richard Biener wrote:
> On Wed, Oct 31, 2012 at 3:18 PM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> On 10/31/2012 10:05 AM, Richard Biener wrote:
>>> On Wed, Oct 31, 2012 at 2:54 PM, Kenneth Zadeck
>>> <zadeck@naturalbridge.com> wrote:
>>>> On 10/31/2012 08:11 AM, Richard Biener wrote:
>>>>> On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford
>>>>> <rdsandiford@googlemail.com> wrote:
>>>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>>> On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford
>>>>>>> <rdsandiford@googlemail.com> wrote:
>>>>>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>>>>> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
>>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>>>>>>>>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump
>>>>>>>>>>> <mikestump@comcast.net>
>>>>>>>>>>> wrote:
>>>>>>>>>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener
>>>>>>>>>>>> <richard.guenther@gmail.com>
>>>>>>>>>>>> wrote:
>>>>>>>>>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>>>>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>>>>>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>>>>>>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> are we sure this rounds properly?  Consider a port with max
>>>>>>>>>>>>>>> byte
>>>>>>>>>>>>>>> mode
>>>>>>>>>>>>>>> size 4 on a 64bit host.
>>>>>>>>>>>>>> I do not believe that this can happen.   The core compiler
>>>>>>>>>>>>>> includes all
>>>>>>>>>>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>>>>>>>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>>>>>>>>>> Actually, no, they are not.  Partial int modes can have bit sizes
>>>>>>>>>>>> that
>>>>>>>>>>>> are not power of two, and, if there isn't an int mode that is
>>>>>>>>>>>> bigger, we'd
>>>>>>>>>>>> want to round up the partial int bit size.  Something like ((2 *
>>>>>>>>>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>>>>>>>>>>> HOST_BITS_PER_WIDE_INT should do it.
>>>>>>>>>>>>
>>>>>>>>>>>>>>> I still would like to have the ability to provide
>>>>>>>>>>>>>>> specializations of
>>>>>>>>>>>>>>> wide_int
>>>>>>>>>>>>>>> for "small" sizes, thus ideally wide_int would be a template
>>>>>>>>>>>>>>> templated
>>>>>>>>>>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2>
>>>>>>>>>>>>>>> should
>>>>>>>>>>>>>>> be
>>>>>>>>>>>>>>> identical to double_int, thus we should be able to do
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> typedef wide_int<2> double_int;
>>>>>>>>>>>>>> If you want to go down this path after the patches get in, go
>>>>>>>>>>>>>> for
>>>>>>>>>>>>>> it.
>>>>>>>>>>>>>> I
>>>>>>>>>>>>>> see no use at all for this.
>>>>>>>>>>>>>> This was not meant to be a plug in replacement for double int.
>>>>>>>>>>>>>> This
>>>>>>>>>>>>>> goal of
>>>>>>>>>>>>>> this patch is to get the compiler to do the constant math the
>>>>>>>>>>>>>> way
>>>>>>>>>>>>>> that
>>>>>>>>>>>>>> the
>>>>>>>>>>>>>> target does it.   Any such instantiation is by definition
>>>>>>>>>>>>>> placing
>>>>>>>>>>>>>> some
>>>>>>>>>>>>>> predefined limit that some target may not want.
>>>>>>>>>>>>> Well, what I don't really like is that we now have two
>>>>>>>>>>>>> implementations
>>>>>>>>>>>>> of functions that perform integer math on two-HWI sized
>>>>>>>>>>>>> integers.
>>>>>>>>>>>>> What
>>>>>>>>>>>>> I also don't like too much is that we have two different
>>>>>>>>>>>>> interfaces to
>>>>>>>>>>>>> operate
>>>>>>>>>>>>> on them!  Can't you see how I come to not liking this?
>>>>>>>>>>>>> Especially
>>>>>>>>>>>>> the
>>>>>>>>>>>>> latter Â…
>>>>>>>>>>>> double_int is logically dead.  Reactoring wide-int and double-int
>>>>>>>>>>>> is a
>>>>>>>>>>>> waste of time, as the time is better spent removing double-int
>>>>>>>>>>>> from
>>>>>>>>>>>> the
>>>>>>>>>>>> compiler.  All the necessary semantics and code of double-int
>>>>>>>>>>>> _has_
>>>>>>>>>>>> been
>>>>>>>>>>>> refactored into wide-int already.  Changing wide-int in any way
>>>>>>>>>>>> to
>>>>>>>>>>>> vend
>>>>>>>>>>>> anything to double-int is wrong, as once double-int is removed,
>>>>>>>>>>>> then all the
>>>>>>>>>>>> api changes to make double-int share from wide-int is wasted and
>>>>>>>>>>>> must then
>>>>>>>>>>>> be removed.  The path forward is the complete removal of
>>>>>>>>>>>> double-int; it is
>>>>>>>>>>>> wrong, has been wrong and always will be wrong, nothing can
>>>>>>>>>>>> change
>>>>>>>>>>>> that.
>>>>>>>>>>> double_int, compared to wide_int, is fast and lean.  I doubt we
>>>>>>>>>>> will
>>>>>>>>>>> get rid of it - you
>>>>>>>>>>> will make compile-time math a _lot_ slower.  Just profile when you
>>>>>>>>>>> for
>>>>>>>>>>> example
>>>>>>>>>>> change get_inner_reference to use wide_ints.
>>>>>>>>>>>
>>>>>>>>>>> To be able to remove double_int in favor of wide_int requires _at
>>>>>>>>>>> least_
>>>>>>>>>>> templating wide_int on 'len' and providing specializations for 1
>>>>>>>>>>> and
>>>>>>>>>>> 2.
>>>>>>>>>>>
>>>>>>>>>>> It might be a non-issue for math that operates on trees or RTXen
>>>>>>>>>>> due
>>>>>>>>>>> to
>>>>>>>>>>> the allocation overhead we pay, but in recent years we
>>>>>>>>>>> transitioned
>>>>>>>>>>> important
>>>>>>>>>>> paths away from using tree math to using double_ints _for speed
>>>>>>>>>>> reasons_.
>>>>>>>>>>>
>>>>>>>>>>> Richard.
>>>>>>>>>> i do not know why you believe this about the speed.     double int
>>>>>>>>>> always
>>>>>>>>>> does synthetic math since you do everything at 128 bit precision.
>>>>>>>>>>
>>>>>>>>>> the thing about wide int, is that since it does math to the
>>>>>>>>>> precision's
>>>>>>>>>> size, it almost never does uses synthetic operations since the
>>>>>>>>>> sizes
>>>>>>>>>> for
>>>>>>>>>> almost every instance can be done using the native math on the
>>>>>>>>>> machine.
>>>>>>>>>> almost every call has a check to see if the operation can be done
>>>>>>>>>> natively.
>>>>>>>>>> I seriously doubt that you are going to do TI mode math much faster
>>>>>>>>>> than i
>>>>>>>>>> do it and if you do who cares.
>>>>>>>>>>
>>>>>>>>>> the number of calls does not effect the performance in any negative
>>>>>>>>>> way and
>>>>>>>>>> it fact is more efficient since common things that require more
>>>>>>>>>> than
>>>>>>>>>> one
>>>>>>>>>> operation in double in are typically done in a single operation.
>>>>>>>>> Simple double-int operations like
>>>>>>>>>
>>>>>>>>> inline double_int
>>>>>>>>> double_int::and_not (double_int b) const
>>>>>>>>> {
>>>>>>>>>      double_int result;
>>>>>>>>>      result.low = low & ~b.low;
>>>>>>>>>      result.high = high & ~b.high;
>>>>>>>>>      return result;
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> are always going to be faster than conditionally executing only one
>>>>>>>>> operation
>>>>>>>>> (but inside an offline function).
>>>>>>>> OK, this is really in reply to the 4.8 thing, but it felt more
>>>>>>>> appropriate here.
>>>>>>>>
>>>>>>>> It's interesting that you gave this example, since before you were
>>>>>>>> complaining about too many fused ops.  Clearly this one could be
>>>>>>>> removed in favour of separate and() and not() operations, but why
>>>>>>>> not provide a fused one if there are clients who'll make use of it?
>>>>>>> I was more concerned about fused operations that use precision
>>>>>>> or bitsize as input.  That is for example
>>>>>>>
>>>>>>>>> +  bool only_sign_bit_p (unsigned int prec) const;
>>>>>>>>> +  bool only_sign_bit_p () const;
>>>>>>> The first is construct a wide-int with precision prec (and sign- or
>>>>>>> zero-extend it) and then call only_sign_bit_p on it.  Such function
>>>>>>> should not be necessary and existing callers should be questioned
>>>>>>> instead of introducing it.
>>>>>>>
>>>>>>> In fact wide-int seems to have so many "fused" operations that
>>>>>>> we run out of sensible recognizable names for them.  Which results
>>>>>>> in a lot of confusion on what the functions actually do (at least for
>>>>>>> me).
>>>>>> Well, I suppose I can't really say anything useful either way on
>>>>>> that one, since I'm not writing the patch and I'm not reviewing it :-)
>>>>>>
>>>>>>>> I think Kenny's API is just taking that to its logical conclusion.
>>>>>>>> There doesn't seem to be anything sacrosanct about the current choice
>>>>>>>> of what's fused and what isn't.
>>>>>>> Maybe.  I'd rather have seen an initial small wide-int API and fused
>>>>>>> operations introduced separately together with the places they are
>>>>>>> used.  In the current way it's way too tedious to go over all of them
>>>>>>> and match them with callers, lookup enough context and then
>>>>>>> make up my mind on whether the caller should do sth different or not.
>>>>>>>
>>>>>>> Thus, consider the big initial API a reason that all this review takes
>>>>>>> so long ...
>>>>>>>
>>>>>>>> The speed problem we had using trees for internal arithmetic isn't
>>>>>>>> IMO a good argument for keeping double_int in preference to wide_int.
>>>>>>>> Allocating and constructing tree objects to hold temporary values,
>>>>>>>> storing an integer representation in it, then calling tree arithmetic
>>>>>>>> routines that pull out the integer representation again and create a
>>>>>>>> tree to hold the result, is going to be much slower than using either
>>>>>>>> double_int or wide_int.  I'd be very surprised if we notice any
>>>>>>>> measurable difference between double_int and wide_int here.
>>>>>>>>
>>>>>>>> I still see no reason to keep double_int around.  The width of a host
>>>>>>>> wide integer really shouldn't have any significance.
>>>>>>>>
>>>>>>>> Your main complaint seems to be that the wide_int API is different
>>>>>>>> from the double_int one, but we can't literally use the same API,
>>>>>>>> since
>>>>>>>> double_int has an implicit precision and bitsize, and wide_int
>>>>>>>> doesn't.
>>>>>>>> Having a precision that is separate from the underlying
>>>>>>>> representation
>>>>>>>> is IMO the most important feature of wide_int, so:
>>>>>>>>
>>>>>>>>       template wide_int<2> double_int;
>>>>>>>>
>>>>>>>> is never going to be a drop-in, API-compatible replacement for
>>>>>>>> double_int.
>>>>>>> My reasoning was that if you strip wide-int of precision and bitsize
>>>>>>> you have a double_int<N> class.
>>>>>> But you don't!  Because...
>>>>>>
>>>>>>> Thus wide-int should have a base
>>>>>>> of that kind and just add precision / bitsize ontop of that.  It
>>>>>>> wouldn't
>>>>>>> be a step forward if we end up replacing double_int uses with
>>>>>>> wide_int uses with precision of 2 * HOST_BITS_PER_WIDE_INT,
>>>>>>> would it?
>>>>>> ...the precision and bitsize isn't an optional extra, either
>>>>>> conceptually
>>>>>> or in implementation.  wide_int happens to use N HOST_WIDE_INTS under
>>>>>> the hood, but the value of N is an internal implementation detail.
>>>>>> No operations are done to N HWIs, they're done to the number of bits
>>>>>> in the operands.  Whereas a double_int<N> class does everything to N
>>>>>> HWIs.
>>>>> If that's the only effect then either bitsize or precision is redundant
>>>>> (and
>>>>> we also have len ...).  Note I did not mention len above, thus the base
>>>>> class would retain 'len' and double-int would simply use 2 for it
>>>>> (if you don't template it but make it variable).
>>>>>
>>>>> Richard.
>>>>>
>>>> NO, in your own words, there are two parts of the compiler that want the
>>>> infinite model.   The rest wants to do the math the way the target does
>>>> it.
>>>> My version now accommodates both.    In tree vrp it scans the gimple and
>>>> determines what the largest type is and that is the basis of all of the
>>>> math
>>>> in this pass.  If you just make double int bigger, then you are paying
>>>> for
>>>> big math everywhere.
>>> You have an artificial limit on what 'len' can be.  And you do not
>>> accomodate
>>> users that do not want to pay the storage penalty for that arbitrary upper
>>> limit
>>> choice.  That's all because 'len' may grow (mutate).  You could
>>> alternatively
>>> not allow bitsize to grow / mutate and have allocation tied to bitsize
>>> instead
>>> of len.
>> It is not artificial, it is based on the target.  I chose to do it that way
>> because i "knew" that having a fixed size would be faster than doing an
>> alloca on for every wide-int.    If we feel that it is important to be able
>> to do truly arbitrary infinite precision arithmetic (as opposed to just some
>> fixed amount larger than the size of the type) then we can have a subclass
>> that does this. However, there is not a need to do this in the compiler
>> currently and so using this as an argument against wide-int is really not
>> fair.
> Well, it is artifical as you had to increase it by a factor of two to handle
> the use in VRP.  It is also "artificial" as it wastes storage.
>
>> However, as the machines allow wider math, your really do not want to
>> penalize every program that is compiled with this burden.   It was ok for
>> double int to do so, but when machines commonly have oi mode, it will still
>> be the case that more than 99% of the variables will be 64 bits or less.
>>
>> I do worry a lot about adding layers like this on the efficiency of the
>> compiler.   you made a valid point that a lot of the double int routines
>> could be done inline and my plan is take the parts of the functions that
>> notice that the precision fits in a hwi and do them inline.
>>
>> If your proposed solution causes a function call to access the elements,
>> then we are doomed.
> Well, if it causes a function call to access a pointer to the array of elements
> which you can cache then it wouldn't be that bad.  And with templates
> we can inline the access anyway.
I do not see how to do this with templates without building in the 
largest template size.


> Richard.
>
>>> Ideally the wide-int interface would have two storage models:
>>>
>>> class alloc_storage
>>> {
>>>     unsigned len; /* or bitsize */
>>>     HOST_WIDE_INT *hwis;
>>>
>>>     HOST_WIDE_INT& operator[](unsigned i) { return hwis[i]; }
>>> }
>>>
>>> class max_mode
>>> {
>>>     HOST_WIDE_INT hwis[largest integer mode size in hwi];
>>>
>>>     HOST_WIDE_INT& operator[](unsigned i) { return hwis[i]; }
>>> }
>>>
>>> template <class storage>
>>> class wide_int : storage
>>> {
>>>
>>> so you can even re-use the (const) in-place storage of INTEGER_CSTs
>>> or RTL CONST_WIDEs.  And VRP would simply have its own storage
>>> supporting 2 times the largest integer mode (or whatever choice it has).
>>> And double-int would simply embed two.
>>>
>>> Maybe this is the perfect example for introducing virtual functions as
>>> well
>>> to ease inter-operability between the wide-int variants without making
>>> each
>>> member a template on the 2nd wide-int operand (it's of course
>>> auto-deduced,
>>> but well ...).
>>>
>>> The above is just a brain-dump, details may need further thinking
>>> Like the operator[], maybe the storage model should just be able
>>> to return a pointer to the array of HWIs, this way the actual workers
>>> can be out-of-line and non-templates.
>>>
>>> Richard.
>>>
>>>>>> Richard
>>>>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 12:50                                                                   ` Richard Biener
  2012-10-31 13:50                                                                     ` Richard Sandiford
@ 2012-10-31 14:39                                                                     ` Kenneth Zadeck
  2012-10-31 19:22                                                                     ` Mike Stump
  2 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-31 14:39 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford


On 10/31/2012 08:44 AM, Richard Biener wrote:
> On Wed, Oct 31, 2012 at 1:22 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>> On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford
>>> <rdsandiford@googlemail.com> wrote:
>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>> On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford
>>>>> <rdsandiford@googlemail.com> wrote:
>>>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>>> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck
>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>> On 10/25/2012 06:42 AM, Richard Biener wrote:
>>>>>>>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump
>>>>>>>>> <mikestump@comcast.net> wrote:
>>>>>>>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guenther@gmail.com>
>>>>>>>>>> wrote:
>>>>>>>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck
>>>>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote:
>>>>>>>>>>>>> +  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT /
>>>>>>>>>>>>> HOST_BITS_PER_WIDE_INT];
>>>>>>>>>>>>>
>>>>>>>>>>>>> are we sure this rounds properly?  Consider a port with max byte mode
>>>>>>>>>>>>> size 4 on a 64bit host.
>>>>>>>>>>>> I do not believe that this can happen.  The core compiler
>>>>>>>>>>>> includes all
>>>>>>>>>>>> modes up to TI mode, so by default we already up to 128 bits.
>>>>>>>>>>> And mode bitsizes are always power-of-two?  I suppose so.
>>>>>>>>>> Actually, no, they are not.  Partial int modes can have bit sizes that
>>>>>>>>>> are not power of two, and, if there isn't an int mode that is
>>>>>>>>>> bigger, we'd
>>>>>>>>>> want to round up the partial int bit size.  Something like ((2 *
>>>>>>>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) /
>>>>>>>>>> HOST_BITS_PER_WIDE_INT should do it.
>>>>>>>>>>
>>>>>>>>>>>>> I still would like to have the ability to provide specializations of
>>>>>>>>>>>>> wide_int
>>>>>>>>>>>>> for "small" sizes, thus ideally wide_int would be a template
>>>>>>>>>>>>> templated
>>>>>>>>>>>>> on the number of HWIs in val.  Interface-wise wide_int<2> should be
>>>>>>>>>>>>> identical to double_int, thus we should be able to do
>>>>>>>>>>>>>
>>>>>>>>>>>>> typedef wide_int<2> double_int;
>>>>>>>>>>>> If you want to go down this path after the patches get in, go for it.
>>>>>>>>>>>> I
>>>>>>>>>>>> see no use at all for this.
>>>>>>>>>>>> This was not meant to be a plug in replacement for double int. This
>>>>>>>>>>>> goal of
>>>>>>>>>>>> this patch is to get the compiler to do the constant math the way that
>>>>>>>>>>>> the
>>>>>>>>>>>> target does it.   Any such instantiation is by definition placing some
>>>>>>>>>>>> predefined limit that some target may not want.
>>>>>>>>>>> Well, what I don't really like is that we now have two implementations
>>>>>>>>>>> of functions that perform integer math on two-HWI sized integers.  What
>>>>>>>>>>> I also don't like too much is that we have two different interfaces to
>>>>>>>>>>> operate
>>>>>>>>>>> on them!  Can't you see how I come to not liking this?  Especially the
>>>>>>>>>>> latter Â…
>>>>>>>>>> double_int is logically dead.  Reactoring wide-int and double-int is a
>>>>>>>>>> waste of time, as the time is better spent removing double-int from the
>>>>>>>>>> compiler.  All the necessary semantics and code of double-int _has_ been
>>>>>>>>>> refactored into wide-int already.  Changing wide-int in any way to vend
>>>>>>>>>> anything to double-int is wrong, as once double-int is removed,
>>>>>>>>>> then all the
>>>>>>>>>> api changes to make double-int share from wide-int is wasted and
>>>>>>>>>> must then
>>>>>>>>>> be removed.  The path forward is the complete removal of
>>>>>>>>>> double-int; it is
>>>>>>>>>> wrong, has been wrong and always will be wrong, nothing can change that.
>>>>>>>>> double_int, compared to wide_int, is fast and lean.  I doubt we will
>>>>>>>>> get rid of it - you
>>>>>>>>> will make compile-time math a _lot_ slower.  Just profile when you for
>>>>>>>>> example
>>>>>>>>> change get_inner_reference to use wide_ints.
>>>>>>>>>
>>>>>>>>> To be able to remove double_int in favor of wide_int requires _at least_
>>>>>>>>> templating wide_int on 'len' and providing specializations for 1 and 2.
>>>>>>>>>
>>>>>>>>> It might be a non-issue for math that operates on trees or RTXen due to
>>>>>>>>> the allocation overhead we pay, but in recent years we transitioned
>>>>>>>>> important
>>>>>>>>> paths away from using tree math to using double_ints _for speed reasons_.
>>>>>>>>>
>>>>>>>>> Richard.
>>>>>>>> i do not know why you believe this about the speed.     double int always
>>>>>>>> does synthetic math since you do everything at 128 bit precision.
>>>>>>>>
>>>>>>>> the thing about wide int, is that since it does math to the precision's
>>>>>>>> size, it almost never does uses synthetic operations since the sizes for
>>>>>>>> almost every instance can be done using the native math on the machine.
>>>>>>>> almost every call has a check to see if the operation can be done
>>>>>>>> natively.
>>>>>>>> I seriously doubt that you are going to do TI mode math much faster than i
>>>>>>>> do it and if you do who cares.
>>>>>>>>
>>>>>>>> the number of calls does not effect the performance in any
>>>>>>>> negative way and
>>>>>>>> it fact is more efficient since common things that require more than one
>>>>>>>> operation in double in are typically done in a single operation.
>>>>>>> Simple double-int operations like
>>>>>>>
>>>>>>> inline double_int
>>>>>>> double_int::and_not (double_int b) const
>>>>>>> {
>>>>>>>    double_int result;
>>>>>>>    result.low = low & ~b.low;
>>>>>>>    result.high = high & ~b.high;
>>>>>>>    return result;
>>>>>>> }
>>>>>>>
>>>>>>> are always going to be faster than conditionally executing only one
>>>>>>> operation
>>>>>>> (but inside an offline function).
>>>>>> OK, this is really in reply to the 4.8 thing, but it felt more
>>>>>> appropriate here.
>>>>>>
>>>>>> It's interesting that you gave this example, since before you were
>>>>>> complaining about too many fused ops.  Clearly this one could be
>>>>>> removed in favour of separate and() and not() operations, but why
>>>>>> not provide a fused one if there are clients who'll make use of it?
>>>>> I was more concerned about fused operations that use precision
>>>>> or bitsize as input.  That is for example
>>>>>
>>>>>>> +  bool only_sign_bit_p (unsigned int prec) const;
>>>>>>> +  bool only_sign_bit_p () const;
>>>>> The first is construct a wide-int with precision prec (and sign- or
>>>>> zero-extend it) and then call only_sign_bit_p on it.  Such function
>>>>> should not be necessary and existing callers should be questioned
>>>>> instead of introducing it.
>>>>>
>>>>> In fact wide-int seems to have so many "fused" operations that
>>>>> we run out of sensible recognizable names for them.  Which results
>>>>> in a lot of confusion on what the functions actually do (at least for me).
>>>> Well, I suppose I can't really say anything useful either way on
>>>> that one, since I'm not writing the patch and I'm not reviewing it :-)
>>>>
>>>>>> I think Kenny's API is just taking that to its logical conclusion.
>>>>>> There doesn't seem to be anything sacrosanct about the current choice
>>>>>> of what's fused and what isn't.
>>>>> Maybe.  I'd rather have seen an initial small wide-int API and fused
>>>>> operations introduced separately together with the places they are
>>>>> used.  In the current way it's way too tedious to go over all of them
>>>>> and match them with callers, lookup enough context and then
>>>>> make up my mind on whether the caller should do sth different or not.
>>>>>
>>>>> Thus, consider the big initial API a reason that all this review takes
>>>>> so long ...
>>>>>
>>>>>> The speed problem we had using trees for internal arithmetic isn't
>>>>>> IMO a good argument for keeping double_int in preference to wide_int.
>>>>>> Allocating and constructing tree objects to hold temporary values,
>>>>>> storing an integer representation in it, then calling tree arithmetic
>>>>>> routines that pull out the integer representation again and create a
>>>>>> tree to hold the result, is going to be much slower than using either
>>>>>> double_int or wide_int.  I'd be very surprised if we notice any
>>>>>> measurable difference between double_int and wide_int here.
>>>>>>
>>>>>> I still see no reason to keep double_int around.  The width of a host
>>>>>> wide integer really shouldn't have any significance.
>>>>>>
>>>>>> Your main complaint seems to be that the wide_int API is different
>>>>>> from the double_int one, but we can't literally use the same API, since
>>>>>> double_int has an implicit precision and bitsize, and wide_int doesn't.
>>>>>> Having a precision that is separate from the underlying representation
>>>>>> is IMO the most important feature of wide_int, so:
>>>>>>
>>>>>>     template wide_int<2> double_int;
>>>>>>
>>>>>> is never going to be a drop-in, API-compatible replacement for double_int.
>>>>> My reasoning was that if you strip wide-int of precision and bitsize
>>>>> you have a double_int<N> class.
>>>> But you don't!  Because...
>>>>
>>>>> Thus wide-int should have a base
>>>>> of that kind and just add precision / bitsize ontop of that.  It wouldn't
>>>>> be a step forward if we end up replacing double_int uses with
>>>>> wide_int uses with precision of 2 * HOST_BITS_PER_WIDE_INT,
>>>>> would it?
>>>> ...the precision and bitsize isn't an optional extra, either conceptually
>>>> or in implementation.  wide_int happens to use N HOST_WIDE_INTS under
>>>> the hood, but the value of N is an internal implementation detail.
>>>> No operations are done to N HWIs, they're done to the number of bits
>>>> in the operands.  Whereas a double_int<N> class does everything to N HWIs.
>>> If that's the only effect then either bitsize or precision is redundant (and
>>> we also have len ...).  Note I did not mention len above, thus the base
>>> class would retain 'len' and double-int would simply use 2 for it
>>> (if you don't template it but make it variable).
>> But that means that wide_int has to model a P-bit operation as a
>> "normal" len*HOST_WIDE_INT operation and then fix up the result
>> after the fact, which seems unnecessarily convoluted.
> It does that right now.  The operations are carried out in a loop
> over len HOST_WIDE_INT parts, the last HWI is then special-treated
> to account for precision/size.  (yes, 'len' is also used as optimization - the
> fact that len ends up being mutable is another thing I dislike about
> wide-int.  If wide-ints are cheap then all ops should be non-mutating
> (at least to 'len')).
There are currently two places where len is mutable.    They are parts 
where i did not believe that i had the expertise to rewrite the double 
int code.    They are in the conversion to and from float and the 
conversion to and from fixed.    In those cases the api is exposed so 
that wide-ints could be built.    I did not think that such temporary 
scaffolding would be the source of ridicule.

All of the uses of wide int as integers are truly functional.

>
>>   I still don't
>> see why a full-precision 2*HOST_WIDE_INT operation (or a full-precision
>> X*HOST_WIDE_INT operation for any X) has any special meaning.
> Well, the same reason as a HOST_WIDE_INT variable has a meaning.
> We use it to constrain what we (efficiently) want to work on.  For example
> CCP might iterate up to 2 * HOST_BITS_PER_WIDE_INT times when
> doing bit-constant-propagation in loops (for TImode integers on a x86_64 host).
>
> Oh, and I don't necessary see a use of double_int in its current form
> but for an integer representation on the host that is efficient to manipulate
> integer constants of a target dependent size.  For example the target
> detail that we have partial integer modes with bitsize > precision and that
> the bits > precision appearantly have a meaning when looking at the
> bit-representation of a constant should not be part of the base class
> of wide-int (I doubt it belongs to wide-int at all, but I guess you know more
> about the reason we track bitsize in addition to precision - I think it's
> abstraction at the wrong level, the tree level does fine without knowing
> about bitsize).
>
> Richard.
>
>> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 13:50                                                                     ` Richard Sandiford
  2012-10-31 13:56                                                                       ` Richard Biener
@ 2012-10-31 15:52                                                                       ` Kenneth Zadeck
  1 sibling, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-10-31 15:52 UTC (permalink / raw)
  To: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford


On 10/31/2012 09:30 AM, Richard Sandiford wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>>> But that means that wide_int has to model a P-bit operation as a
>>> "normal" len*HOST_WIDE_INT operation and then fix up the result
>>> after the fact, which seems unnecessarily convoluted.
>> It does that right now.  The operations are carried out in a loop
>> over len HOST_WIDE_INT parts, the last HWI is then special-treated
>> to account for precision/size.  (yes, 'len' is also used as optimization - the
>> fact that len ends up being mutable is another thing I dislike about
>> wide-int.  If wide-ints are cheap then all ops should be non-mutating
>> (at least to 'len')).
> But the point of having a mutating len is that things like zero and -1
> are common even for OImode values.  So if you're doing someting potentially
> expensive like OImode multiplication, why do it to the number of
> HOST_WIDE_INTs needed for an OImode value when the value we're
> processing has only one significant HOST_WIDE_INT?
I think with a little thought i can add some special constructors and 
get rid of the mutating aspects of the interface.

>
>>>   I still don't
>>> see why a full-precision 2*HOST_WIDE_INT operation (or a full-precision
>>> X*HOST_WIDE_INT operation for any X) has any special meaning.
>> Well, the same reason as a HOST_WIDE_INT variable has a meaning.
>> We use it to constrain what we (efficiently) want to work on.  For example
>> CCP might iterate up to 2 * HOST_BITS_PER_WIDE_INT times when
>> doing bit-constant-propagation in loops (for TImode integers on a x86_64 host).
> But what about targets with modes wider than TImode?  Would double_int
> still be appropriate then?  If not, why does CCP have to use a templated
> type with a fixed number of HWIs (and all arithmetic done to a fixed
> number of HWIs) rather than one that can adapt to the runtime values,
> like wide_int can?
>
>> Oh, and I don't necessary see a use of double_int in its current form
>> but for an integer representation on the host that is efficient to manipulate
>> integer constants of a target dependent size.  For example the target
>> detail that we have partial integer modes with bitsize > precision and that
>> the bits > precision appearantly have a meaning when looking at the
>> bit-representation of a constant should not be part of the base class
>> of wide-int (I doubt it belongs to wide-int at all, but I guess you know more
>> about the reason we track bitsize in addition to precision - I think it's
>> abstraction at the wrong level, the tree level does fine without knowing
>> about bitsize).
> TBH I'm uneasy about the bitsize thing too.  I think bitsize is only
> tracked for shift truncation, and if so, I agree it makes sense
> to do that separately.
>
> But anyway, this whole discussion seems to have reached a stalemate.
> Or I suppose a de-facto rejection, since you're the only person in
> a position to approve the thing :-)
>
> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 12:50                                                                   ` Richard Biener
  2012-10-31 13:50                                                                     ` Richard Sandiford
  2012-10-31 14:39                                                                     ` Kenneth Zadeck
@ 2012-10-31 19:22                                                                     ` Mike Stump
  2 siblings, 0 replies; 217+ messages in thread
From: Mike Stump @ 2012-10-31 19:22 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kenneth Zadeck, gcc-patches, Lawrence Crowl, rdsandiford

On Oct 31, 2012, at 5:44 AM, Richard Biener <richard.guenther@gmail.com> wrote:
> the
> fact that len ends up being mutable is another thing I dislike about
> wide-int.

We expose len for construction only, it is non-mutating.  During construction, there is no previous value.

>  If wide-ints are cheap then all ops should be non-mutating
> (at least to 'len')).

It is.  Construction modifies the object as construction must be defined as initializing the state of the data.  Before construction, there is no data, so, we are constructing the data, not mutating the data.  Surely you don't object to construction?

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 13:56                                                                       ` Richard Biener
  2012-10-31 14:26                                                                         ` Kenneth Zadeck
@ 2012-10-31 19:45                                                                         ` Mike Stump
  1 sibling, 0 replies; 217+ messages in thread
From: Mike Stump @ 2012-10-31 19:45 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kenneth Zadeck, gcc-patches, Lawrence Crowl, rdsandiford

On Oct 31, 2012, at 6:54 AM, Richard Biener <richard.guenther@gmail.com> wrote:
> I propose that no wide-int member function
> may _change_ it's len (to something larger).

We never do that, so, we already do as you wish.  We construct wide ints, and we have member functions to construct values.  We need to construct values as some parts of the compiler want to create values.  The construction of values can be removed when the rest of the compiler no longer wishes to construct values. LTO is an example of a client that wanted to construct a value.  I'll let the LTO people chime in if they wish to no loner construct values.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 14:07                                                                   ` Richard Biener
  2012-10-31 14:25                                                                     ` Kenneth Zadeck
@ 2012-10-31 20:07                                                                     ` Mike Stump
  1 sibling, 0 replies; 217+ messages in thread
From: Mike Stump @ 2012-10-31 20:07 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kenneth Zadeck, gcc-patches, Lawrence Crowl, rdsandiford

On Oct 31, 2012, at 7:05 AM, Richard Biener <richard.guenther@gmail.com> wrote:
> You have an artificial limit on what 'len' can be.

No.  There is no limit, and nothing artificial.  We take the maximum of the needs of the target, the maximum of the front-ends and the maximum of the mid-end and the back-end.  We can drop a category, if that category no longer wishes to be our client.  Any client is free to stop using wide-int, any time they want.  For example, vrp could use gmp, if they wanted to, and the need to serve them drops.  You have imagined the cost is high to do this, the reality is all long lived objects are small, and all short lived objects are so transitory that we are talking about maybe 5 live at a time.

> And you do not accomodate
> users that do not want to pay the storage penalty for that arbitrary upper limit
> choice.

This is also wrong.  First, there is no arbitrary upper limit.  Second, all long lived objects are small.  We accommodated them by having all long lived objects be small.  The transitory objects are big, but there are only 5 of them alive at a time.

>  That's all because 'len' may grow (mutate).

This is also wrong.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 8th patch - tree-vrp.c
  2012-10-31 14:25                                                                       ` Richard Biener
  2012-10-31 14:30                                                                         ` Kenneth Zadeck
@ 2012-11-01 22:13                                                                         ` Kenneth Zadeck
  2012-11-01 22:28                                                                           ` Marc Glisse
  2012-11-01 22:33                                                                           ` patch to fix constant math - 4th patch - wide-int.[ch] refresh Kenneth Zadeck
  2012-11-30 16:46                                                                         ` patch to fix constant math - 4th patch - the wide-int class Kenneth Zadeck
  2013-02-27  1:59                                                                         ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Kenneth Zadeck
  3 siblings, 2 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-11-01 22:13 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Marc Glisse

[-- Attachment #1: Type: text/plain, Size: 3647 bytes --]

This patch converts tree-vpn to use wide-int.   In doing so it gets rid 
of all restrictions that this pass currently has on the target or source 
word size.

The pass's reliance on a finite "infinite precision" representation has 
been preserved.  It first scans the function being compiled to determine 
the largest type that needs to be represented within that function and 
then it uses some multiple of that size as it's definition of infinite.

I am currently using 4 for this value.   However marc glisse claims that 
this may be due to a bug and that the value should be 2. This is 
something that has to be investigated further.   This could easily be my 
mistake or some other issue that has crept into the pass.  The value of 
2 or 4 is easily changed in largest_initialize.    The only truly non 
mechanical transformation is in the code that multiplies two ranges.   
This code uses the wide-int multiply full functions rather than using 
pairs of double-ints.

Most of the changes in the first part of the changelog relate to 
changing of external functions to return wide-ints rather than 
double-ints since c++ does not have result polymorphism.

This patch depends on a freshened version of the wide-int class.

This patch has been bootstrapped and tested on x86-64.

kenny

2012-11-1  Kenneth Zadeck <zadeck@naturalbridge.com>

     * builtins.c (get_object_alignment_2, fold_builtin_memory_op):
     Renamed mem_ref_offset to mem_ref_offset_as_double.
     * cfgloop.h (max_loop_iterations): Changed to take wide_int param.
     * expr.c (get_inner_reference, expand_expr_real_1): Renamed
     mem_ref_offset to mem_ref_offset_as_double.
     * gimple-fold.c (get_base_constructor): Ditto.
     * gimple-ssa-strength-reduction.c (restructure_reference): Ditto.
     * ipa-prop.c (compute_complex_assign_jump_func, 
get_ancestor_addr_info):
     Ditto.
     * tree-data-ref.c (dr_analyze_innermost): Ditto.
     * tree-dfa.c (get_ref_base_and_extent): Ditto.
     * tree-flow-inline.h (get_addr_base_and_unit_offset_1): Ditto.
     * tree-object-size.c (compute_object_offset, addr_object_size): Ditto.
     * tree-sra.c (sra_ipa_modify_expr): Ditto.
     * tree-ssa-address.c (copy_ref_info): Ditto.
     * tree-ssa-alias.c (indirect_ref_may_alias_decl_p): Ditto.
     * tree-ssa-forwprop.c (forward_propagate_addr_expr_1,
     constant_pointer_difference): Ditto.
     * tree-ssa-loop-niter.c (max_loop_iterations): New function.
     * tree-ssa-phiopt.c (jump_function_from_stmt): Ditto.
     * tree-ssa-sccvn.c (vn_reference_maybe_forwprop_address): Ditto.
     * tree-ssa.c (non_rewritable_mem_ref_base): Ditto.
     * tree-vect-data-refs.c (vect_check_gather): Ditto.
     * tree-vrp.c (largest_precision, largest_bitsize): New variables.
     (tree_to_infinite_wide_int, look_for_largest, largest_initialize):
     New functions.
     (extract_range_from_assert, vrp_int_const_binop,
     zero_nonzero_bits_from_vr, ranges_from_anti_range,
     extract_range_from_multiplicative_op_1,
     extract_range_from_binary_expr_1, adjust_range_with_scev,
     register_new_assert_for, extract_code_and_val_from_cond_with_ops,
     register_edge_assert_for_2, search_for_addr_array,
     search_for_addr_array, simplify_bit_ops_using_ranges,
     simplify_switch_using_ranges, simplify_conversion_using_ranges,
     range_fits_type_p, range_fits_type_p,
     simplify_float_conversion_using_ranges, execute_vrp): Convert from
     double-int operations to wide-int operations.
     * tree.c (wide_int_to_infinite_tree): New function.
     * varasm.c (decode_addr_const): Renamed mem_ref_offset to
     mem_ref_offset_as_double.



[-- Attachment #2: p8-2.diff --]
[-- Type: text/x-patch, Size: 79687 bytes --]

diff --git a/gcc/builtins.c b/gcc/builtins.c
index c1722ab..f5c9418 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -378,7 +378,7 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
 	  bitpos += ptr_bitpos;
 	  if (TREE_CODE (exp) == MEM_REF
 	      || TREE_CODE (exp) == TARGET_MEM_REF)
-	    bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT;
+	    bitpos += mem_ref_offset_as_double (exp).low * BITS_PER_UNIT;
 	}
     }
   else if (TREE_CODE (exp) == STRING_CST)
@@ -8784,12 +8784,12 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
 		  if (! operand_equal_p (TREE_OPERAND (src_base, 0),
 					 TREE_OPERAND (dest_base, 0), 0))
 		    return NULL_TREE;
-		  off = mem_ref_offset (src_base) +
+		  off = mem_ref_offset_as_double (src_base) +
 					double_int::from_shwi (src_offset);
 		  if (!off.fits_shwi ())
 		    return NULL_TREE;
 		  src_offset = off.low;
-		  off = mem_ref_offset (dest_base) +
+		  off = mem_ref_offset_as_double (dest_base) +
 					double_int::from_shwi (dest_offset);
 		  if (!off.fits_shwi ())
 		    return NULL_TREE;
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index e0a370f..dd3748a 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "basic-block.h"
 #include "vecprim.h"
 #include "double-int.h"
+#include "wide-int.h"
 
 #include "bitmap.h"
 #include "sbitmap.h"
@@ -288,6 +289,7 @@ void estimate_numbers_of_iterations_loop (struct loop *);
 void record_niter_bound (struct loop *, double_int, bool, bool);
 bool estimated_loop_iterations (struct loop *, double_int *);
 bool max_loop_iterations (struct loop *, double_int *);
+bool max_loop_iterations (struct loop *, wide_int *, int, int);
 HOST_WIDE_INT estimated_loop_iterations_int (struct loop *);
 HOST_WIDE_INT max_loop_iterations_int (struct loop *);
 bool max_stmt_executions (struct loop *, double_int *);
diff --git a/gcc/expr.c b/gcc/expr.c
index fe27819..31adc26 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6678,7 +6678,7 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
 	      tree off = TREE_OPERAND (exp, 1);
 	      if (!integer_zerop (off))
 		{
-		  double_int boff, coff = mem_ref_offset (exp);
+		  double_int boff, coff = mem_ref_offset_as_double (exp);
 		  boff = coff.alshift (BITS_PER_UNIT == 8
 				       ? 3 : exact_log2 (BITS_PER_UNIT),
 				       HOST_BITS_PER_DOUBLE_INT);
@@ -9533,7 +9533,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 	   might end up in a register.  */
 	if (mem_ref_refers_to_non_mem_p (exp))
 	  {
-	    HOST_WIDE_INT offset = mem_ref_offset (exp).low;
+	    HOST_WIDE_INT offset = mem_ref_offset_as_double (exp).low;
 	    tree bit_offset;
 	    tree bftype;
 	    base = TREE_OPERAND (base, 0);
@@ -9577,8 +9577,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 	op0 = memory_address_addr_space (address_mode, op0, as);
 	if (!integer_zerop (TREE_OPERAND (exp, 1)))
 	  {
-	    wide_int wi = wide_int::from_double_int
-	      (mem_ref_offset (exp), address_mode);
+	    wide_int wi = mem_ref_offset (exp);
 	    rtx off = immed_wide_int_const (wi, address_mode);
 	    op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
 	  }
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 5ff70a2..57f3914 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -2688,7 +2688,7 @@ get_base_constructor (tree base, HOST_WIDE_INT *bit_offset,
 	{
 	  if (!tree_fits_shwi_p (TREE_OPERAND (base, 1)))
 	    return NULL_TREE;
-	  *bit_offset += (mem_ref_offset (base).low
+	  *bit_offset += (mem_ref_offset_as_double (base).low
 			  * BITS_PER_UNIT);
 	}
 
diff --git a/gcc/gimple-ssa-strength-reduction.c b/gcc/gimple-ssa-strength-reduction.c
index 6ee5c7a..eb141c0 100644
--- a/gcc/gimple-ssa-strength-reduction.c
+++ b/gcc/gimple-ssa-strength-reduction.c
@@ -557,7 +557,7 @@ restructure_reference (tree *pbase, tree *poffset, double_int *pindex,
     return false;
 
   t1 = TREE_OPERAND (base, 0);
-  c1 = mem_ref_offset (base);
+  c1 = mem_ref_offset_as_double (base);
   type = TREE_TYPE (TREE_OPERAND (base, 1));
 
   mult_op0 = TREE_OPERAND (offset, 0);
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 633cbc4..243847e 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -933,7 +933,7 @@ compute_complex_assign_jump_func (struct ipa_node_params *info,
       || max_size == -1
       || max_size != size)
     return;
-  offset += mem_ref_offset (base).low * BITS_PER_UNIT;
+  offset += mem_ref_offset_as_double (base).low * BITS_PER_UNIT;
   ssa = TREE_OPERAND (base, 0);
   if (TREE_CODE (ssa) != SSA_NAME
       || !SSA_NAME_IS_DEFAULT_DEF (ssa)
@@ -988,7 +988,7 @@ get_ancestor_addr_info (gimple assign, tree *obj_p, HOST_WIDE_INT *offset)
       || TREE_CODE (SSA_NAME_VAR (parm)) != PARM_DECL)
     return NULL_TREE;
 
-  *offset += mem_ref_offset (expr).low * BITS_PER_UNIT;
+  *offset += mem_ref_offset_as_double (expr).low * BITS_PER_UNIT;
   *obj_p = obj;
   return expr;
 }
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index b606210..42ad127 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -720,7 +720,7 @@ dr_analyze_innermost (struct data_reference *dr, struct loop *nest)
     {
       if (!integer_zerop (TREE_OPERAND (base, 1)))
 	{
-	  double_int moff = mem_ref_offset (base);
+	  double_int moff = mem_ref_offset_as_double (base);
 	  tree mofft = double_int_to_tree (sizetype, moff);
 	  if (!poffset)
 	    poffset = mofft;
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 9be06aa..03814bc 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -552,7 +552,7 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
 		exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
 	      else
 		{
-		  double_int off = mem_ref_offset (exp);
+		  double_int off = mem_ref_offset_as_double (exp);
 		  off = off.alshift (BITS_PER_UNIT == 8
 				     ? 3 : exact_log2 (BITS_PER_UNIT),
 				     HOST_BITS_PER_DOUBLE_INT);
@@ -583,7 +583,7 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
 		exp = TREE_OPERAND (TMR_BASE (exp), 0);
 	      else
 		{
-		  double_int off = mem_ref_offset (exp);
+		  double_int off = mem_ref_offset_as_double (exp);
 		  off = off.alshift (BITS_PER_UNIT == 8
 				     ? 3 : exact_log2 (BITS_PER_UNIT),
 				     HOST_BITS_PER_DOUBLE_INT);
diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h
index a433223..1e59aa1 100644
--- a/gcc/tree-flow-inline.h
+++ b/gcc/tree-flow-inline.h
@@ -1269,7 +1269,7 @@ get_addr_base_and_unit_offset_1 (tree exp, HOST_WIDE_INT *poffset,
 	      {
 		if (!integer_zerop (TREE_OPERAND (exp, 1)))
 		  {
-		    double_int off = mem_ref_offset (exp);
+		    double_int off = mem_ref_offset_as_double (exp);
 		    gcc_assert (off.high == -1 || off.high == 0);
 		    byte_offset += off.to_shwi ();
 		  }
@@ -1292,7 +1292,7 @@ get_addr_base_and_unit_offset_1 (tree exp, HOST_WIDE_INT *poffset,
 		  return NULL_TREE;
 		if (!integer_zerop (TMR_OFFSET (exp)))
 		  {
-		    double_int off = mem_ref_offset (exp);
+		    double_int off = mem_ref_offset_as_double (exp);
 		    gcc_assert (off.high == -1 || off.high == 0);
 		    byte_offset += off.to_shwi ();
 		  }
diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index c9e30f7..1a4a4d9 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -142,7 +142,7 @@ compute_object_offset (const_tree expr, const_tree var)
 
     case MEM_REF:
       gcc_assert (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR);
-      return double_int_to_tree (sizetype, mem_ref_offset (expr));
+      return double_int_to_tree (sizetype, mem_ref_offset_as_double (expr));
 
     default:
       return error_mark_node;
@@ -192,7 +192,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
 	}
       if (sz != unknown[object_size_type])
 	{
-	  double_int dsz = double_int::from_uhwi (sz) - mem_ref_offset (pt_var);
+	  double_int dsz = double_int::from_uhwi (sz) - mem_ref_offset_as_double (pt_var);
 	  if (dsz.is_negative ())
 	    sz = 0;
 	  else if (dsz.fits_uhwi ())
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index a172d91..5ccecbc 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -4304,7 +4304,7 @@ sra_ipa_modify_expr (tree *expr, bool convert,
 
   if (TREE_CODE (base) == MEM_REF)
     {
-      offset += mem_ref_offset (base).low * BITS_PER_UNIT;
+      offset += mem_ref_offset_as_double (base).low * BITS_PER_UNIT;
       base = TREE_OPERAND (base, 0);
     }
 
diff --git a/gcc/tree-ssa-address.c b/gcc/tree-ssa-address.c
index 932c1e1..c7875ee 100644
--- a/gcc/tree-ssa-address.c
+++ b/gcc/tree-ssa-address.c
@@ -869,8 +869,8 @@ copy_ref_info (tree new_ref, tree old_ref)
 			   && (tree_to_shwi (TMR_STEP (new_ref))
 			       < align)))))
 	    {
-	      unsigned int inc = (mem_ref_offset (old_ref)
-				  - mem_ref_offset (new_ref)).low;
+	      unsigned int inc = (mem_ref_offset_as_double (old_ref)
+				  - mem_ref_offset_as_double (new_ref)).low;
 	      adjust_ptr_info_misalignment (new_pi, inc);
 	    }
 	  else
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 6eabb70..8624ce2 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -755,7 +755,7 @@ indirect_ref_may_alias_decl_p (tree ref1 ATTRIBUTE_UNUSED, tree base1,
 
   /* The offset embedded in MEM_REFs can be negative.  Bias them
      so that the resulting offset adjustment is positive.  */
-  moff = mem_ref_offset (base1);
+  moff = mem_ref_offset_as_double (base1);
   moff = moff.alshift (BITS_PER_UNIT == 8
 		       ? 3 : exact_log2 (BITS_PER_UNIT),
 		       HOST_BITS_PER_DOUBLE_INT);
@@ -833,7 +833,7 @@ indirect_ref_may_alias_decl_p (tree ref1 ATTRIBUTE_UNUSED, tree base1,
   if (TREE_CODE (dbase2) == MEM_REF
       || TREE_CODE (dbase2) == TARGET_MEM_REF)
     {
-      double_int moff = mem_ref_offset (dbase2);
+      double_int moff = mem_ref_offset_as_double (dbase2);
       moff = moff.alshift (BITS_PER_UNIT == 8
 			   ? 3 : exact_log2 (BITS_PER_UNIT),
 			   HOST_BITS_PER_DOUBLE_INT);
@@ -929,7 +929,7 @@ indirect_refs_may_alias_p (tree ref1 ATTRIBUTE_UNUSED, tree base1,
       double_int moff;
       /* The offset embedded in MEM_REFs can be negative.  Bias them
 	 so that the resulting offset adjustment is positive.  */
-      moff = mem_ref_offset (base1);
+      moff = mem_ref_offset_as_double (base1);
       moff = moff.alshift (BITS_PER_UNIT == 8
 			   ? 3 : exact_log2 (BITS_PER_UNIT),
 			   HOST_BITS_PER_DOUBLE_INT);
@@ -937,7 +937,7 @@ indirect_refs_may_alias_p (tree ref1 ATTRIBUTE_UNUSED, tree base1,
 	offset2 += (-moff).low;
       else
 	offset1 += moff.low;
-      moff = mem_ref_offset (base2);
+      moff = mem_ref_offset_as_double (base2);
       moff = moff.alshift (BITS_PER_UNIT == 8
 			   ? 3 : exact_log2 (BITS_PER_UNIT),
 			   HOST_BITS_PER_DOUBLE_INT);
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index 703325a..601641e 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -799,12 +799,12 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
       if ((def_rhs_base = get_addr_base_and_unit_offset (TREE_OPERAND (def_rhs, 0),
 							 &def_rhs_offset)))
 	{
-	  double_int off = mem_ref_offset (lhs);
+	  double_int off = mem_ref_offset_as_double (lhs);
 	  tree new_ptr;
 	  off += double_int::from_shwi (def_rhs_offset);
 	  if (TREE_CODE (def_rhs_base) == MEM_REF)
 	    {
-	      off += mem_ref_offset (def_rhs_base);
+	      off += mem_ref_offset_as_double (def_rhs_base);
 	      new_ptr = TREE_OPERAND (def_rhs_base, 0);
 	    }
 	  else
@@ -883,12 +883,12 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
       if ((def_rhs_base = get_addr_base_and_unit_offset (TREE_OPERAND (def_rhs, 0),
 							 &def_rhs_offset)))
 	{
-	  double_int off = mem_ref_offset (rhs);
+	  double_int off = mem_ref_offset_as_double (rhs);
 	  tree new_ptr;
 	  off += double_int::from_shwi (def_rhs_offset);
 	  if (TREE_CODE (def_rhs_base) == MEM_REF)
 	    {
-	      off += mem_ref_offset (def_rhs_base);
+	      off += mem_ref_offset_as_double (def_rhs_base);
 	      new_ptr = TREE_OPERAND (def_rhs_base, 0);
 	    }
 	  else
@@ -1352,7 +1352,7 @@ constant_pointer_difference (tree p1, tree p2)
 		  p = TREE_OPERAND (q, 0);
 		  off = size_binop (PLUS_EXPR, off,
 				    double_int_to_tree (sizetype,
-							mem_ref_offset (q)));
+							mem_ref_offset_as_double (q)));
 		}
 	      else
 		{
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index fe4db37..27e2d71 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -3035,6 +3035,23 @@ max_loop_iterations (struct loop *loop, double_int *nit)
   return true;
 }
 
+/* Sets NIT to an upper bound for the maximum number of executions of the
+   latch of the LOOP.  If we have no reliable estimate, the function returns
+   false, otherwise returns true.  */
+
+bool
+max_loop_iterations (struct loop *loop, wide_int *nit,
+		     int bitsize, int precision)
+{
+  estimate_numbers_of_iterations_loop (loop);
+  if (!loop->any_upper_bound)
+    return false;
+
+  *nit = wide_int::from_double_int (loop->nb_iterations_upper_bound,
+				    bitsize, precision);
+  return true;
+}
+
 /* Similar to estimated_loop_iterations, but returns the estimate only
    if it fits to HOST_WIDE_INT.  If this is not the case, or the estimate
    on the number of iterations of LOOP could not be derived, returns -1.  */
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
index e3e90d5..3055b1e 100644
--- a/gcc/tree-ssa-phiopt.c
+++ b/gcc/tree-ssa-phiopt.c
@@ -702,7 +702,7 @@ jump_function_from_stmt (tree *arg, gimple stmt)
 						&offset);
       if (tem
 	  && TREE_CODE (tem) == MEM_REF
-	  && (mem_ref_offset (tem) + double_int::from_shwi (offset)).is_zero ())
+	  && (mem_ref_offset_as_double (tem) + double_int::from_shwi (offset)).is_zero ())
 	{
 	  *arg = TREE_OPERAND (tem, 0);
 	  return true;
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 837fe6d..91fc76b 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -1124,7 +1124,7 @@ vn_reference_maybe_forwprop_address (VEC (vn_reference_op_s, heap) **ops,
 	return;
 
       off += double_int::from_shwi (addr_offset);
-      off += mem_ref_offset (addr_base);
+      off += mem_ref_offset_as_double (addr_base);
       op->op0 = TREE_OPERAND (addr_base, 0);
     }
   else
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 7ba11e1..1fee91e 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -1833,9 +1833,9 @@ non_rewritable_mem_ref_base (tree ref)
 	   || TREE_CODE (TREE_TYPE (decl)) == COMPLEX_TYPE)
 	  && useless_type_conversion_p (TREE_TYPE (base),
 					TREE_TYPE (TREE_TYPE (decl)))
-	  && mem_ref_offset (base).fits_uhwi ()
+	  && mem_ref_offset_as_double (base).fits_uhwi ()
 	  && tree_to_double_int (TYPE_SIZE_UNIT (TREE_TYPE (decl)))
-	     .ugt (mem_ref_offset (base))
+	     .ugt (mem_ref_offset_as_double (base))
 	  && multiple_of_p (sizetype, TREE_OPERAND (base, 1),
 			    TYPE_SIZE_UNIT (TREE_TYPE (base))))
 	return NULL_TREE;
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index d93c5b7..d16e345 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -2730,7 +2730,7 @@ vect_check_gather (gimple stmt, loop_vec_info loop_vinfo, tree *basep,
 	{
 	  if (off == NULL_TREE)
 	    {
-	      double_int moff = mem_ref_offset (base);
+	      double_int moff = mem_ref_offset_as_double (base);
 	      off = double_int_to_tree (sizetype, moff);
 	    }
 	  else
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 9003ac5..85d6f6d 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -80,6 +80,12 @@ typedef struct value_range_d value_range_t;
    for still active basic-blocks.  */
 static sbitmap *live;
 
+/* The largest precision and bitsize used in any code in this
+   function.  We use these to determine the value of infinity for
+   doing infinite precision math.  */
+static int largest_precision;
+static int largest_bitsize;
+
 /* Return true if the SSA name NAME is live on the edge E.  */
 
 static bool
@@ -387,6 +393,15 @@ nonnull_arg_p (const_tree arg)
   return false;
 }
 
+/* Convert a cst to an infinitely sized wide_interger.  Infinite is
+   defined to be that largest type seen in this function.  */
+static wide_int
+tree_to_infinite_wide_int (const_tree cst)
+{
+  wide_int result = wide_int::from_tree_as_infinite_precision
+    (cst, largest_bitsize, largest_precision);
+  return result;
+}
 
 /* Set value range VR to VR_UNDEFINED.  */
 
@@ -967,7 +982,7 @@ gimple_assign_nonnegative_warnv_p (gimple stmt, bool *strict_overflow_p)
     }
 }
 
-/* Return true if return value of call STMT is know to be non-negative.
+/* Return true if return value of call STMT is known to be non-negative.
    If the return value is based on the assumption that signed overflow is
    undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
    *STRICT_OVERFLOW_P.*/
@@ -987,7 +1002,7 @@ gimple_call_nonnegative_warnv_p (gimple stmt, bool *strict_overflow_p)
 					strict_overflow_p);
 }
 
-/* Return true if STMT is know to to compute a non-negative value.
+/* Return true if STMT is known to to compute a non-negative value.
    If the return value is based on the assumption that signed overflow is
    undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
    *STRICT_OVERFLOW_P.*/
@@ -1006,7 +1021,7 @@ gimple_stmt_nonnegative_warnv_p (gimple stmt, bool *strict_overflow_p)
     }
 }
 
-/* Return true if the result of assignment STMT is know to be non-zero.
+/* Return true if the result of assignment STMT is known to be non-zero.
    If the return value is based on the assumption that signed overflow is
    undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
    *STRICT_OVERFLOW_P.*/
@@ -1040,7 +1055,7 @@ gimple_assign_nonzero_warnv_p (gimple stmt, bool *strict_overflow_p)
     }
 }
 
-/* Return true if STMT is know to to compute a non-zero value.
+/* Return true if STMT is known to to compute a non-zero value.
    If the return value is based on the assumption that signed overflow is
    undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
    *STRICT_OVERFLOW_P.*/
@@ -1613,10 +1628,12 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
       /* Make sure to not set TREE_OVERFLOW on the final type
 	 conversion.  We are willingly interpreting large positive
 	 unsigned values as negative singed values here.  */
-      min = force_fit_type_double (TREE_TYPE (var), tree_to_double_int (min),
-				   0, false);
-      max = force_fit_type_double (TREE_TYPE (var), tree_to_double_int (max),
-				   0, false);
+      min = wide_int_to_infinite_tree (TREE_TYPE (var), 
+				       tree_to_infinite_wide_int (min),
+				       largest_precision);
+      max = wide_int_to_infinite_tree (TREE_TYPE (var), 
+				       tree_to_infinite_wide_int (max),
+				       largest_precision);
 
       /* We can transform a max, min range to an anti-range or
          vice-versa.  Use set_and_canonicalize_value_range which does
@@ -1962,7 +1979,7 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
 }
 
 
-/* For range VR compute two double_int bitmasks.  In *MAY_BE_NONZERO
+/* For range VR compute two wide_int bitmasks.  In *MAY_BE_NONZERO
    bitmask if some bit is unset, it means for all numbers in the range
    the bit is 0, otherwise it might be 0 or 1.  In *MUST_BE_NONZERO
    bitmask if some bit is set, it means for all numbers in the range
@@ -1970,11 +1987,11 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
 
 static bool
 zero_nonzero_bits_from_vr (value_range_t *vr,
-			   double_int *may_be_nonzero,
-			   double_int *must_be_nonzero)
+			   wide_int *may_be_nonzero,
+			   wide_int *must_be_nonzero)
 {
-  *may_be_nonzero = double_int_minus_one;
-  *must_be_nonzero = double_int_zero;
+  *may_be_nonzero = wide_int::minus_one (largest_bitsize, largest_precision);
+  *must_be_nonzero = wide_int::zero (largest_bitsize, largest_precision);
   if (!range_int_cst_p (vr)
       || TREE_OVERFLOW (vr->min)
       || TREE_OVERFLOW (vr->max))
@@ -1982,34 +1999,24 @@ zero_nonzero_bits_from_vr (value_range_t *vr,
 
   if (range_int_cst_singleton_p (vr))
     {
-      *may_be_nonzero = tree_to_double_int (vr->min);
+      *may_be_nonzero = tree_to_infinite_wide_int (vr->min);
       *must_be_nonzero = *may_be_nonzero;
     }
   else if (tree_int_cst_sgn (vr->min) >= 0
 	   || tree_int_cst_sgn (vr->max) < 0)
     {
-      double_int dmin = tree_to_double_int (vr->min);
-      double_int dmax = tree_to_double_int (vr->max);
-      double_int xor_mask = dmin ^ dmax;
+      wide_int dmin = tree_to_infinite_wide_int (vr->min);
+      wide_int dmax = tree_to_infinite_wide_int (vr->max);
+      wide_int xor_mask = dmin ^ dmax;
       *may_be_nonzero = dmin | dmax;
       *must_be_nonzero = dmin & dmax;
-      if (xor_mask.high != 0)
+      if (!xor_mask.zero_p ())
 	{
-	  unsigned HOST_WIDE_INT mask
-	      = ((unsigned HOST_WIDE_INT) 1
-		 << floor_log2 (xor_mask.high)) - 1;
-	  may_be_nonzero->low = ALL_ONES;
-	  may_be_nonzero->high |= mask;
-	  must_be_nonzero->low = 0;
-	  must_be_nonzero->high &= ~mask;
-	}
-      else if (xor_mask.low != 0)
-	{
-	  unsigned HOST_WIDE_INT mask
-	      = ((unsigned HOST_WIDE_INT) 1
-		 << floor_log2 (xor_mask.low)) - 1;
-	  may_be_nonzero->low |= mask;
-	  must_be_nonzero->low &= ~mask;
+	  wide_int mask = wide_int::mask (xor_mask.floor_log2 (), 
+					  false, largest_bitsize, 
+					  largest_precision);
+	  *may_be_nonzero = (*may_be_nonzero) | mask;
+	  *must_be_nonzero = (*must_be_nonzero).and_not (mask);
 	}
     }
 
@@ -2042,15 +2049,21 @@ ranges_from_anti_range (value_range_t *ar,
       vr0->type = VR_RANGE;
       vr0->min = vrp_val_min (type);
       vr0->max
-	= double_int_to_tree (type,
-			      tree_to_double_int (ar->min) - double_int_one);
+	= wide_int_to_infinite_tree (type,
+				     tree_to_infinite_wide_int (ar->min) 
+				     - wide_int::one (largest_bitsize, 
+						      largest_precision),
+				     largest_precision);
     }
   if (!vrp_val_is_max (ar->max))
     {
       vr1->type = VR_RANGE;
       vr1->min
-	= double_int_to_tree (type,
-			      tree_to_double_int (ar->max) + double_int_one);
+	= wide_int_to_infinite_tree (type,
+				     tree_to_infinite_wide_int (ar->max) 
+				     + wide_int::one (largest_bitsize, 
+						      largest_precision),
+				     largest_precision);
       vr1->max = vrp_val_max (type);
     }
   if (vr0->type == VR_UNDEFINED)
@@ -2216,28 +2229,6 @@ extract_range_from_multiplicative_op_1 (value_range_t *vr,
     set_value_range (vr, type, min, max, NULL);
 }
 
-/* Some quadruple precision helpers.  */
-static int
-quad_int_cmp (double_int l0, double_int h0,
-	      double_int l1, double_int h1, bool uns)
-{
-  int c = h0.cmp (h1, uns);
-  if (c != 0) return c;
-  return l0.ucmp (l1);
-}
-
-static void
-quad_int_pair_sort (double_int *l0, double_int *h0,
-		    double_int *l1, double_int *h1, bool uns)
-{
-  if (quad_int_cmp (*l0, *h0, *l1, *h1, uns) > 0)
-    {
-      double_int tmp;
-      tmp = *l0; *l0 = *l1; *l1 = tmp;
-      tmp = *h0; *h0 = *h1; *h1 = tmp;
-    }
-}
-
 /* Extract range information from a binary operation CODE based on
    the ranges of each of its operands, *VR0 and *VR1 with resulting
    type EXPR_TYPE.  The resulting range is stored in *VR.  */
@@ -2252,6 +2243,8 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
   enum value_range_type type;
   tree min = NULL_TREE, max = NULL_TREE;
   int cmp;
+  wide_int::SignOp sgn = TYPE_UNSIGNED (expr_type) 
+    ? wide_int::UNSIGNED : wide_int::UNSIGNED;
 
   if (!INTEGRAL_TYPE_P (expr_type)
       && !POINTER_TYPE_P (expr_type))
@@ -2407,32 +2400,34 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
       /* If we have a PLUS_EXPR with two VR_RANGE integer constant
          ranges compute the precise range for such case if possible.  */
       if (range_int_cst_p (&vr0)
-	  && range_int_cst_p (&vr1)
-	  /* We need as many bits as the possibly unsigned inputs.  */
-	  && TYPE_PRECISION (expr_type) <= HOST_BITS_PER_DOUBLE_INT)
-	{
-	  double_int min0 = tree_to_double_int (vr0.min);
-	  double_int max0 = tree_to_double_int (vr0.max);
-	  double_int min1 = tree_to_double_int (vr1.min);
-	  double_int max1 = tree_to_double_int (vr1.max);
-	  bool uns = TYPE_UNSIGNED (expr_type);
-	  double_int type_min
-	    = double_int::min_value (TYPE_PRECISION (expr_type), uns);
-	  double_int type_max
-	    = double_int::max_value (TYPE_PRECISION (expr_type), uns);
-	  double_int dmin, dmax;
+	  && range_int_cst_p (&vr1))
+	{
+	  wide_int min0 = tree_to_infinite_wide_int (vr0.min);
+	  wide_int max0 = tree_to_infinite_wide_int (vr0.max);
+	  wide_int min1 = tree_to_infinite_wide_int (vr1.min);
+	  wide_int max1 = tree_to_infinite_wide_int (vr1.max);
+	  wide_int::SignOp uns = TYPE_UNSIGNED (expr_type) 
+	    ? wide_int::UNSIGNED : wide_int::SIGNED;
+	  wide_int type_min = wide_int::min_value (expr_type)
+	    .force_to_size (largest_bitsize, largest_precision, uns)
+	    .ext (TYPE_PRECISION (expr_type), uns);
+	  wide_int type_max = wide_int::max_value (expr_type)
+	    .force_to_size (largest_bitsize, largest_precision, uns)
+	    .ext (TYPE_PRECISION (expr_type), wide_int::UNSIGNED);
+	  wide_int dmin, dmax;
 	  int min_ovf = 0;
 	  int max_ovf = 0;
+	  wide_int zero = wide_int::zero (largest_bitsize, largest_precision);
 
 	  if (code == PLUS_EXPR)
 	    {
 	      dmin = min0 + min1;
 	      dmax = max0 + max1;
 
-	      /* Check for overflow in double_int.  */
-	      if (min1.cmp (double_int_zero, uns) != dmin.cmp (min0, uns))
+	      /* Check for overflow in wide_int.  */
+	      if (min1.cmp (zero, uns) != dmin.cmp (min0, uns))
 		min_ovf = min0.cmp (dmin, uns);
-	      if (max1.cmp (double_int_zero, uns) != dmax.cmp (max0, uns))
+	      if (max1.cmp (zero, uns) != dmax.cmp (max0, uns))
 		max_ovf = max0.cmp (dmax, uns);
 	    }
 	  else /* if (code == MINUS_EXPR) */
@@ -2440,9 +2435,9 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 	      dmin = min0 - max1;
 	      dmax = max0 - min1;
 
-	      if (double_int_zero.cmp (max1, uns) != dmin.cmp (min0, uns))
+	      if (zero.cmp (max1, uns) != dmin.cmp (min0, uns))
 		min_ovf = min0.cmp (max1, uns);
-	      if (double_int_zero.cmp (min1, uns) != dmax.cmp (max0, uns))
+	      if (zero.cmp (min1, uns) != dmax.cmp (max0, uns))
 		max_ovf = max0.cmp (min1, uns);
 	    }
 
@@ -2451,9 +2446,9 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 	  if (!TYPE_OVERFLOW_WRAPS (expr_type))
 	    {
 	      if (vrp_val_min (expr_type))
-		type_min = tree_to_double_int (vrp_val_min (expr_type));
+		type_min = tree_to_infinite_wide_int (vrp_val_min (expr_type));
 	      if (vrp_val_max (expr_type))
-		type_max = tree_to_double_int (vrp_val_max (expr_type));
+		type_max = tree_to_infinite_wide_int (vrp_val_max (expr_type));
 	    }
 
 	  /* Check for type overflow.  */
@@ -2476,19 +2471,16 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 	    {
 	      /* If overflow wraps, truncate the values and adjust the
 		 range kind and bounds appropriately.  */
-	      double_int tmin
-		= dmin.ext (TYPE_PRECISION (expr_type), uns);
-	      double_int tmax
-		= dmax.ext (TYPE_PRECISION (expr_type), uns);
+	      wide_int tmin = dmin.ext (TYPE_PRECISION (expr_type), uns);
+	      wide_int tmax = dmax.ext (TYPE_PRECISION (expr_type), uns);
 	      if (min_ovf == max_ovf)
 		{
 		  /* No overflow or both overflow or underflow.  The
 		     range kind stays VR_RANGE.  */
-		  min = double_int_to_tree (expr_type, tmin);
-		  max = double_int_to_tree (expr_type, tmax);
+		  min = wide_int_to_infinite_tree (expr_type, tmin, largest_precision);
+		  max = wide_int_to_infinite_tree (expr_type, tmax, largest_precision);
 		}
-	      else if (min_ovf == -1
-		       && max_ovf == 1)
+	      else if (min_ovf == -1 && max_ovf == 1)
 		{
 		  /* Underflow and overflow, drop to VR_VARYING.  */
 		  set_value_range_to_varying (vr);
@@ -2499,26 +2491,30 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 		  /* Min underflow or max overflow.  The range kind
 		     changes to VR_ANTI_RANGE.  */
 		  bool covers = false;
-		  double_int tem = tmin;
+		  wide_int tem = tmin;
 		  gcc_assert ((min_ovf == -1 && max_ovf == 0)
 			      || (max_ovf == 1 && min_ovf == 0));
 		  type = VR_ANTI_RANGE;
-		  tmin = tmax + double_int_one;
-		  if (tmin.cmp (tmax, uns) < 0)
+		  tmin = tmax + wide_int::one (largest_bitsize, 
+					       largest_precision);
+		  if (tmin.lt_p (tmax, uns))
 		    covers = true;
-		  tmax = tem + double_int_minus_one;
-		  if (tmax.cmp (tem, uns) > 0)
+		  tmax = tem + wide_int::minus_one (largest_bitsize, 
+						    largest_precision);
+		  if (tmax.gt_p (tem, uns))
 		    covers = true;
 		  /* If the anti-range would cover nothing, drop to varying.
 		     Likewise if the anti-range bounds are outside of the
 		     types values.  */
-		  if (covers || tmin.cmp (tmax, uns) > 0)
+		  if (covers || tmin.gt_p (tmax, uns))
 		    {
 		      set_value_range_to_varying (vr);
 		      return;
 		    }
-		  min = double_int_to_tree (expr_type, tmin);
-		  max = double_int_to_tree (expr_type, tmax);
+		  min = wide_int_to_infinite_tree (expr_type, tmin,
+						   largest_precision);
+		  max = wide_int_to_infinite_tree (expr_type, tmax, 
+						   largest_precision);
 		}
 	    }
 	  else
@@ -2531,7 +2527,8 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 		      && supports_overflow_infinity (expr_type))
 		    min = negative_overflow_infinity (expr_type);
 		  else
-		    min = double_int_to_tree (expr_type, type_min);
+		    min = wide_int_to_infinite_tree (expr_type, type_min, 
+						     largest_precision);
 		}
 	      else if (min_ovf == 1)
 		{
@@ -2539,10 +2536,12 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 		      && supports_overflow_infinity (expr_type))
 		    min = positive_overflow_infinity (expr_type);
 		  else
-		    min = double_int_to_tree (expr_type, type_max);
+		    min = wide_int_to_infinite_tree (expr_type, type_max,
+						     largest_precision);
 		}
 	      else
-		min = double_int_to_tree (expr_type, dmin);
+		min = wide_int_to_infinite_tree (expr_type, dmin,
+						 largest_precision);
 
 	      if (max_ovf == -1)
 		{
@@ -2550,7 +2549,8 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 		      && supports_overflow_infinity (expr_type))
 		    max = negative_overflow_infinity (expr_type);
 		  else
-		    max = double_int_to_tree (expr_type, type_min);
+		    max = wide_int_to_infinite_tree (expr_type, type_min,
+						     largest_precision);
 		}
 	      else if (max_ovf == 1)
 		{
@@ -2558,10 +2558,12 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 		      && supports_overflow_infinity (expr_type))
 		    max = positive_overflow_infinity (expr_type);
 		  else
-		    max = double_int_to_tree (expr_type, type_max);
+		    max = wide_int_to_infinite_tree (expr_type, type_max,
+						     largest_precision);
 		}
 	      else
-		max = double_int_to_tree (expr_type, dmax);
+		max = wide_int_to_infinite_tree (expr_type, dmax,
+						 largest_precision);
 	    }
 	  if (needs_overflow_infinity (expr_type)
 	      && supports_overflow_infinity (expr_type))
@@ -2624,92 +2626,133 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 	  && range_int_cst_p (&vr1)
 	  && TYPE_OVERFLOW_WRAPS (expr_type))
 	{
-	  double_int min0, max0, min1, max1, sizem1, size;
-	  double_int prod0l, prod0h, prod1l, prod1h,
-		     prod2l, prod2h, prod3l, prod3h;
-	  bool uns0, uns1, uns;
-
-	  sizem1 = double_int::max_value (TYPE_PRECISION (expr_type), true);
-	  size = sizem1 + double_int_one;
+	  wide_int min0, max0, min1, max1, sizem1, size;
+	  wide_int prod0, prod1, prod2, prod3;
+	  wide_int::SignOp uns0, uns1, uns;
+
+	  /* The largest_precision and the largest_bitsize are already
+	     twice the size of the largest type that has been seen in
+	     this function.  We do not need to multiply them by a
+	     factor of two again to do this analysis.  So we trim them
+	     down to the size of the largest types seen and then we
+	     will fix things up at the end.  */
+
+	  int bs2 = largest_bitsize*2;
+	  int prec2 = largest_precision*2;
+
+	  /* Use the mode here to force the unsigned max value.  */
+	  sizem1 = wide_int::max_value (TYPE_MODE (expr_type), wide_int::UNSIGNED)
+	    .force_to_size (largest_bitsize, largest_precision, wide_int::UNSIGNED)
+	    .zext (TYPE_PRECISION (expr_type));
+	  size = sizem1 + wide_int::one (largest_bitsize, largest_precision);
+
+	  uns0 = TYPE_UNSIGNED (expr_type) 
+	    ? wide_int::UNSIGNED : wide_int::SIGNED;
+
+	  min0 = tree_to_infinite_wide_int (vr0.min)
+	    .force_to_size (largest_bitsize, largest_precision, uns0);
+	  max0 = tree_to_infinite_wide_int (vr0.max)
+	    .force_to_size (largest_bitsize, largest_precision, uns0);
+	  min1 = tree_to_infinite_wide_int (vr1.min)
+	    .force_to_size (largest_bitsize, largest_precision, uns0);
+	  max1 = tree_to_infinite_wide_int (vr1.max)
+	    .force_to_size (largest_bitsize, largest_precision, uns0);
 
-	  min0 = tree_to_double_int (vr0.min);
-	  max0 = tree_to_double_int (vr0.max);
-	  min1 = tree_to_double_int (vr1.min);
-	  max1 = tree_to_double_int (vr1.max);
-
-	  uns0 = TYPE_UNSIGNED (expr_type);
 	  uns1 = uns0;
 
 	  /* Canonicalize the intervals.  */
 	  if (TYPE_UNSIGNED (expr_type))
 	    {
-	      double_int min2 = size - min0;
-	      if (min2.cmp (max0, true) < 0)
+	      wide_int min2 = size - min0;
+	      if (min2.ltu_p (max0))
 		{
-		  min0 = -min2;
-		  max0 -= size;
-		  uns0 = false;
+		  min0 = min2.neg ();
+		  max0 = max0 - size;
+		  uns0 = wide_int::SIGNED;
 		}
 
 	      min2 = size - min1;
-	      if (min2.cmp (max1, true) < 0)
+	      if (min2.ltu_p (max1))
 		{
-		  min1 = -min2;
-		  max1 -= size;
-		  uns1 = false;
+		  min1 = min2.neg();
+		  max1 = max1 - size;
+		  uns1 = wide_int::SIGNED;
 		}
 	    }
-	  uns = uns0 & uns1;
-
-	  bool overflow;
-	  prod0l = min0.wide_mul_with_sign (min1, true, &prod0h, &overflow);
-	  if (!uns0 && min0.is_negative ())
-	    prod0h -= min1;
-	  if (!uns1 && min1.is_negative ())
-	    prod0h -= min0;
-
-	  prod1l = min0.wide_mul_with_sign (max1, true, &prod1h, &overflow);
-	  if (!uns0 && min0.is_negative ())
-	    prod1h -= max1;
-	  if (!uns1 && max1.is_negative ())
-	    prod1h -= min0;
-
-	  prod2l = max0.wide_mul_with_sign (min1, true, &prod2h, &overflow);
-	  if (!uns0 && max0.is_negative ())
-	    prod2h -= min1;
-	  if (!uns1 && min1.is_negative ())
-	    prod2h -= max0;
-
-	  prod3l = max0.wide_mul_with_sign (max1, true, &prod3h, &overflow);
-	  if (!uns0 && max0.is_negative ())
-	    prod3h -= max1;
-	  if (!uns1 && max1.is_negative ())
-	    prod3h -= max0;
-
-	  /* Sort the 4 products.  */
-	  quad_int_pair_sort (&prod0l, &prod0h, &prod3l, &prod3h, uns);
-	  quad_int_pair_sort (&prod1l, &prod1h, &prod2l, &prod2h, uns);
-	  quad_int_pair_sort (&prod0l, &prod0h, &prod1l, &prod1h, uns);
-	  quad_int_pair_sort (&prod2l, &prod2h, &prod3l, &prod3h, uns);
 
-	  /* Max - min.  */
-	  if (prod0l.is_zero ())
+	  uns = ((uns0 == wide_int::UNSIGNED) & (uns1 == wide_int::UNSIGNED))
+	    ? wide_int::UNSIGNED : wide_int::SIGNED;
+
+	  prod0 = min0.umul_full (min1);
+	  if (uns0 == wide_int::SIGNED && min0.neg_p ())
+	    prod0 = prod0 - min1.lshift (largest_precision, wide_int::NONE, 
+					 bs2, prec2);
+	  if (uns1 == wide_int::SIGNED && min1.neg_p ())
+	    prod0 = prod0 - min0.lshift (largest_precision, wide_int::NONE, 
+					 bs2, prec2);
+
+	  prod1 = min0.umul_full (max1);
+	  if (uns0 == wide_int::SIGNED && min0.neg_p ())
+	    prod1 = prod1 - max1.lshift (largest_precision, wide_int::NONE, 
+					 bs2, prec2);
+	  if (uns1 == wide_int::SIGNED && max1.neg_p ())
+	    prod1 = prod1 - min0.lshift (largest_precision, wide_int::NONE, 
+					 bs2, prec2);
+
+	  prod2 = max0.umul_full (min1);
+	  if (uns0 == wide_int::SIGNED && max0.neg_p ())
+	    prod2 = prod2 - min1.lshift (largest_precision, wide_int::NONE, 
+					 bs2, prec2);
+	  if (uns1 == wide_int::SIGNED && min1.neg_p ())
+	    prod2 = prod2 - max0.lshift (largest_precision, wide_int::NONE, 
+					 bs2, prec2);
+
+	  prod3 = max0.umul_full (max1);
+	  if (uns0 == wide_int::SIGNED && max0.neg_p ())
+	    prod3 = prod3 - max1.lshift (largest_precision, wide_int::NONE, 
+					 bs2, prec2);
+	  if (uns1 == wide_int::SIGNED && max1.neg_p ())
+	    prod3 = prod3 - max0.lshift (largest_precision, wide_int::NONE, 
+					 bs2, prec2);
+
+	  /* Sort the 4 products so that min is in prod0 and max is in
+	     prod3.  */
+
+	  /* min0min1 > max0max1 */
+	  if (!prod0.lt_p (prod3, uns))
 	    {
-	      prod1l = double_int_zero;
-	      prod1h = -prod0h;
+	      wide_int tmp = prod0;
+	      prod0 = prod3;
+	      prod3 = tmp;
 	    }
-	  else
+	  
+	  /* min0max1 > max0min1 */
+	  if (!prod1.lt_p (prod2, uns))
 	    {
-	      prod1l = -prod0l;
-	      prod1h = ~prod0h;
+	      wide_int tmp = prod1;
+	      prod1 = prod2;
+	      prod2 = tmp;
 	    }
-	  prod2l = prod3l + prod1l;
-	  prod2h = prod3h + prod1h;
-	  if (prod2l.ult (prod3l))
-	    prod2h += double_int_one; /* carry */
 
-	  if (!prod2h.is_zero ()
-	      || prod2l.cmp (sizem1, true) >= 0)
+	  if (!prod0.lt_p (prod1, uns))
+	    {
+	      wide_int tmp = prod0;
+	      prod0 = prod1;
+	      prod1 = tmp;
+	    }
+
+	  if (!prod2.lt_p (prod3, uns))
+	    {
+	      wide_int tmp = prod2;
+	      prod2 = prod3;
+	      prod3 = tmp;
+	    }
+
+	  /* Max - min.  */
+	  prod2 = prod3 - prod0;
+	  if (sizem1.force_to_size (bs2, prec2, 
+				    wide_int::UNSIGNED)
+	      .ltu_p (prod2))
 	    {
 	      /* the range covers all values.  */
 	      set_value_range_to_varying (vr);
@@ -2718,8 +2761,10 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 
 	  /* The following should handle the wrapping and selecting
 	     VR_ANTI_RANGE for us.  */
-	  min = double_int_to_tree (expr_type, prod0l);
-	  max = double_int_to_tree (expr_type, prod3l);
+	  min = wide_int_to_infinite_tree (expr_type, prod0,
+					   prec2);
+	  max = wide_int_to_infinite_tree (expr_type, prod3,
+					   prec2);
 	  set_and_canonicalize_value_range (vr, VR_RANGE, min, max, NULL);
 	  return;
 	}
@@ -2766,11 +2811,11 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 	      bool saved_flag_wrapv;
 	      value_range_t vr1p = VR_INITIALIZER;
 	      vr1p.type = VR_RANGE;
-	      vr1p.min
-		= double_int_to_tree (expr_type,
-				      double_int_one
-				      .llshift (tree_to_shwi (vr1.min),
-					        TYPE_PRECISION (expr_type)));
+	      vr1p.min = wide_int_to_infinite_tree 
+		(expr_type,
+		 wide_int::set_bit_in_zero (tree_to_uhwi (vr1.min),
+					    largest_bitsize, largest_precision),
+		 largest_precision);
 	      vr1p.max = vr1p.min;
 	      /* We have to use a wrapping multiply though as signed overflow
 		 on lshifts is implementation defined in C89.  */
@@ -2787,7 +2832,7 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 	      int prec = TYPE_PRECISION (expr_type);
 	      int overflow_pos = prec;
 	      int bound_shift;
-	      double_int bound, complement, low_bound, high_bound;
+	      wide_int bound, complement, low_bound, high_bound;
 	      bool uns = TYPE_UNSIGNED (expr_type);
 	      bool in_bounds = false;
 
@@ -2800,21 +2845,23 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 		 zero, which means vr1 is a singleton range of zero, which
 		 means it should be handled by the previous LSHIFT_EXPR
 		 if-clause.  */
-	      bound = double_int_one.llshift (bound_shift, prec);
-	      complement = ~(bound - double_int_one);
+	      bound = wide_int::set_bit_in_zero (bound_shift, 
+						 largest_bitsize, 
+						 largest_precision);
+	      complement = bound.neg ();
 
 	      if (uns)
 		{
 		  low_bound = bound;
 		  high_bound = complement.zext (prec);
-		  if (tree_to_double_int (vr0.max).ult (low_bound))
+		  if (tree_to_infinite_wide_int (vr0.max).ltu_p (low_bound))
 		    {
 		      /* [5, 6] << [1, 2] == [10, 24].  */
 		      /* We're shifting out only zeroes, the value increases
 			 monotonically.  */
 		      in_bounds = true;
 		    }
-		  else if (high_bound.ult (tree_to_double_int (vr0.min)))
+		  else if (high_bound.ltu_p (tree_to_infinite_wide_int (vr0.min)))
 		    {
 		      /* [0xffffff00, 0xffffffff] << [1, 2]
 		         == [0xfffffc00, 0xfffffffe].  */
@@ -2828,8 +2875,8 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 		  /* [-1, 1] << [1, 2] == [-4, 4].  */
 		  low_bound = complement.sext (prec);
 		  high_bound = bound;
-		  if (tree_to_double_int (vr0.max).slt (high_bound)
-		      && low_bound.slt (tree_to_double_int (vr0.min)))
+		  if (tree_to_infinite_wide_int (vr0.max).lts_p (high_bound)
+		      && low_bound.lts_p (tree_to_infinite_wide_int (vr0.min)))
 		    {
 		      /* For non-negative numbers, we're shifting out only
 			 zeroes, the value increases monotonically.
@@ -2965,8 +3012,8 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
   else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR)
     {
       bool int_cst_range0, int_cst_range1;
-      double_int may_be_nonzero0, may_be_nonzero1;
-      double_int must_be_nonzero0, must_be_nonzero1;
+      wide_int may_be_nonzero0, may_be_nonzero1;
+      wide_int must_be_nonzero0, must_be_nonzero1;
 
       int_cst_range0 = zero_nonzero_bits_from_vr (&vr0, &may_be_nonzero0,
 						  &must_be_nonzero0);
@@ -2976,10 +3023,13 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
       type = VR_RANGE;
       if (code == BIT_AND_EXPR)
 	{
-	  double_int dmax;
-	  min = double_int_to_tree (expr_type,
-				    must_be_nonzero0 & must_be_nonzero1);
+	  wide_int dmax;
+	    
+	  min = wide_int_to_infinite_tree (expr_type,
+					   must_be_nonzero0 & must_be_nonzero1,
+					   largest_precision);
 	  dmax = may_be_nonzero0 & may_be_nonzero1;
+
 	  /* If both input ranges contain only negative values we can
 	     truncate the result range maximum to the minimum of the
 	     input range maxima.  */
@@ -2987,27 +3037,26 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 	      && tree_int_cst_sgn (vr0.max) < 0
 	      && tree_int_cst_sgn (vr1.max) < 0)
 	    {
-	      dmax = dmax.min (tree_to_double_int (vr0.max),
-				     TYPE_UNSIGNED (expr_type));
-	      dmax = dmax.min (tree_to_double_int (vr1.max),
-				     TYPE_UNSIGNED (expr_type));
+	      dmax = dmax.min (tree_to_infinite_wide_int (vr0.max), sgn);
+	      dmax = dmax.min (tree_to_infinite_wide_int (vr1.max), sgn);
 	    }
 	  /* If either input range contains only non-negative values
 	     we can truncate the result range maximum to the respective
 	     maximum of the input range.  */
 	  if (int_cst_range0 && tree_int_cst_sgn (vr0.min) >= 0)
-	    dmax = dmax.min (tree_to_double_int (vr0.max),
-				   TYPE_UNSIGNED (expr_type));
+	    dmax = dmax.min (tree_to_infinite_wide_int (vr0.max), sgn);
+
 	  if (int_cst_range1 && tree_int_cst_sgn (vr1.min) >= 0)
-	    dmax = dmax.min (tree_to_double_int (vr1.max),
-				   TYPE_UNSIGNED (expr_type));
-	  max = double_int_to_tree (expr_type, dmax);
+	    dmax = dmax.min (tree_to_infinite_wide_int (vr1.max), sgn);
+	  max = wide_int_to_infinite_tree (expr_type, dmax,
+					   largest_precision);
 	}
       else if (code == BIT_IOR_EXPR)
 	{
-	  double_int dmin;
-	  max = double_int_to_tree (expr_type,
-				    may_be_nonzero0 | may_be_nonzero1);
+	  wide_int dmin;
+	  max = wide_int_to_infinite_tree (expr_type, 
+					   may_be_nonzero0 | may_be_nonzero1,
+					   largest_precision);
 	  dmin = must_be_nonzero0 | must_be_nonzero1;
 	  /* If the input ranges contain only positive values we can
 	     truncate the minimum of the result range to the maximum
@@ -3016,35 +3065,35 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
 	      && tree_int_cst_sgn (vr0.min) >= 0
 	      && tree_int_cst_sgn (vr1.min) >= 0)
 	    {
-	      dmin = dmin.max (tree_to_double_int (vr0.min),
-			       TYPE_UNSIGNED (expr_type));
-	      dmin = dmin.max (tree_to_double_int (vr1.min),
-			       TYPE_UNSIGNED (expr_type));
+	      dmin = dmin.max (tree_to_infinite_wide_int (vr0.min), sgn);
+	      dmin = dmin.max (tree_to_infinite_wide_int (vr1.min), sgn);
 	    }
 	  /* If either input range contains only negative values
 	     we can truncate the minimum of the result range to the
 	     respective minimum range.  */
 	  if (int_cst_range0 && tree_int_cst_sgn (vr0.max) < 0)
-	    dmin = dmin.max (tree_to_double_int (vr0.min),
-			     TYPE_UNSIGNED (expr_type));
+	    dmin = dmin.max (tree_to_infinite_wide_int (vr0.min), sgn);
 	  if (int_cst_range1 && tree_int_cst_sgn (vr1.max) < 0)
-	    dmin = dmin.max (tree_to_double_int (vr1.min),
-			     TYPE_UNSIGNED (expr_type));
-	  min = double_int_to_tree (expr_type, dmin);
+	    dmin = dmin.max (tree_to_infinite_wide_int (vr1.min), sgn);
+	  min = wide_int_to_infinite_tree (expr_type, dmin,
+					   largest_precision);
 	}
       else if (code == BIT_XOR_EXPR)
 	{
-	  double_int result_zero_bits, result_one_bits;
-	  result_zero_bits = (must_be_nonzero0 & must_be_nonzero1)
-			     | ~(may_be_nonzero0 | may_be_nonzero1);
-	  result_one_bits = must_be_nonzero0.and_not (may_be_nonzero1)
-			    | must_be_nonzero1.and_not (may_be_nonzero0);
-	  max = double_int_to_tree (expr_type, ~result_zero_bits);
-	  min = double_int_to_tree (expr_type, result_one_bits);
+	  wide_int result_zero_bits, result_one_bits;
+	  result_zero_bits
+	    = (must_be_nonzero0 & must_be_nonzero1).or_not
+	    (may_be_nonzero0 | may_be_nonzero1);
+	  result_one_bits
+	    = must_be_nonzero0.and_not (may_be_nonzero1)
+	    | must_be_nonzero1.and_not (may_be_nonzero0);
+	  max = wide_int_to_infinite_tree (expr_type, ~result_zero_bits,
+					   largest_precision);
+	  min = wide_int_to_infinite_tree (expr_type, result_one_bits,
+					   largest_precision);
 	  /* If the range has all positive or all negative values the
 	     result is better than VARYING.  */
-	  if (tree_int_cst_sgn (min) < 0
-	      || tree_int_cst_sgn (max) >= 0)
+	  if (tree_int_cst_sgn (min) < 0 || tree_int_cst_sgn (max) >= 0)
 	    ;
 	  else
 	    max = min = NULL_TREE;
@@ -3252,18 +3301,27 @@ extract_range_from_unary_expr_1 (value_range_t *vr,
 		         size_int (TYPE_PRECISION (outer_type)))))))
 	{
 	  tree new_min, new_max;
+	  wide_int::SignOp inner_type_sgn = 
+	    TYPE_UNSIGNED (inner_type) ? wide_int::UNSIGNED : wide_int::SIGNED;
+	  /* We want to extend these from the inner type to the outer
+	     type using the signedness of the inner type but the
+	     precision of the outer type.  */
 	  if (is_overflow_infinity (vr0.min))
 	    new_min = negative_overflow_infinity (outer_type);
 	  else
-	    new_min = force_fit_type_double (outer_type,
-					     tree_to_double_int (vr0.min),
-					     0, false);
+	    new_min = wide_int_to_infinite_tree 
+	      (outer_type,
+	       tree_to_infinite_wide_int (vr0.min)
+	       .ext (TYPE_PRECISION (outer_type), inner_type_sgn),
+	       largest_precision);
 	  if (is_overflow_infinity (vr0.max))
 	    new_max = positive_overflow_infinity (outer_type);
 	  else
-	    new_max = force_fit_type_double (outer_type,
-					     tree_to_double_int (vr0.max),
-					     0, false);
+	    new_max = wide_int_to_infinite_tree
+	      (outer_type,
+	       tree_to_infinite_wide_int (vr0.max)
+	       .ext (TYPE_PRECISION (outer_type), inner_type_sgn),
+	       largest_precision);
 	  set_and_canonicalize_value_range (vr, vr0.type,
 					    new_min, new_max, NULL);
 	  return;
@@ -3660,30 +3718,33 @@ adjust_range_with_scev (value_range_t *vr, struct loop *loop,
       && (TREE_CODE (init) != SSA_NAME
 	  || get_value_range (init)->type == VR_RANGE))
     {
-      double_int nit;
+      wide_int nit;
+      wide_int wstep = tree_to_infinite_wide_int (step); 
 
       /* We are only entering here for loop header PHI nodes, so using
 	 the number of latch executions is the correct thing to use.  */
-      if (max_loop_iterations (loop, &nit))
+      if (max_loop_iterations (loop, &nit,
+			       wstep.get_bitsize (), wstep.get_precision()))
 	{
 	  value_range_t maxvr = VR_INITIALIZER;
-	  double_int dtmp;
-	  bool unsigned_p = TYPE_UNSIGNED (TREE_TYPE (step));
+	  wide_int dtmp;
+	  wide_int::SignOp uns = TYPE_UNSIGNED (TREE_TYPE (step)) 
+	    ? wide_int::UNSIGNED : wide_int::SIGNED;
 	  bool overflow = false;
 
-	  dtmp = tree_to_double_int (step)
-		 .mul_with_sign (nit, unsigned_p, &overflow);
+	  dtmp = wstep.mul (nit, uns, &overflow);
 	  /* If the multiplication overflowed we can't do a meaningful
 	     adjustment.  Likewise if the result doesn't fit in the type
 	     of the induction variable.  For a signed type we have to
 	     check whether the result has the expected signedness which
 	     is that of the step as number of iterations is unsigned.  */
 	  if (!overflow
-	      && double_int_fits_to_tree_p (TREE_TYPE (init), dtmp)
-	      && (unsigned_p
-		  || ((dtmp.high ^ TREE_INT_CST_HIGH (step)) >= 0)))
+	      && dtmp.fits_to_tree_p (TREE_TYPE (init))
+	      && (TYPE_UNSIGNED (TREE_TYPE (step))
+		  || (dtmp.neg_p () == tree_int_cst_sign_bit (step))))
 	    {
-	      tem = double_int_to_tree (TREE_TYPE (init), dtmp);
+	      tem = wide_int_to_infinite_tree (TREE_TYPE (init), dtmp,
+					       largest_precision);
 	      extract_range_from_binary_expr (&maxvr, PLUS_EXPR,
 					      TREE_TYPE (init), init, tem);
 	      /* Likewise if the addition did.  */
@@ -4404,9 +4465,9 @@ register_new_assert_for (tree name, tree expr,
      machinery.  */
   if (TREE_CODE (val) == INTEGER_CST
       && TREE_OVERFLOW (val))
-    val = build_int_cst_wide (TREE_TYPE (val),
-			      TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val));
-
+    val = wide_int_to_infinite_tree
+      (TREE_TYPE (val), tree_to_infinite_wide_int (val), largest_precision);
+  
   /* The new assertion A will be inserted at BB or E.  We need to
      determine if the new location is dominated by a previously
      registered location for A.  If we are doing an edge insertion,
@@ -4558,23 +4619,27 @@ extract_code_and_val_from_cond_with_ops (tree name, enum tree_code cond_code,
    (to transform signed values into unsigned) and at the end xor
    SGNBIT back.  */
 
-static double_int
-masked_increment (double_int val, double_int mask, double_int sgnbit,
-		  unsigned int prec)
+static wide_int
+masked_increment (const wide_int &val_in, const wide_int &mask_in, 
+		  const wide_int &sgnbit, const_tree type)
 {
-  double_int bit = double_int_one, res;
+  wide_int val = val_in.zext (TYPE_PRECISION (type));
+  wide_int mask = mask_in.zext (TYPE_PRECISION (type));
+  wide_int one = wide_int::one (largest_bitsize, largest_precision);
+  wide_int bit = one, res;
+  unsigned int prec = TYPE_PRECISION (type);
   unsigned int i;
 
-  val ^= sgnbit;
-  for (i = 0; i < prec; i++, bit += bit)
+  val = val ^ sgnbit;
+  for (i = 0; i < prec; i++, bit = bit + bit)
     {
       res = mask;
-      if ((res & bit).is_zero ())
+      if ((res & bit).zero_p())
 	continue;
-      res = bit - double_int_one;
+      res = bit - one;
       res = (val + bit).and_not (res);
-      res &= mask;
-      if (res.ugt (val))
+      res = res & mask;
+      if (res.gtu_p (val))
 	return res ^ sgnbit;
     }
   return val ^ sgnbit;
@@ -4710,8 +4775,12 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
       gimple def_stmt = SSA_NAME_DEF_STMT (name);
       tree name2 = NULL_TREE, names[2], cst2 = NULL_TREE;
       tree val2 = NULL_TREE;
-      double_int mask = double_int_zero;
-      unsigned int prec = TYPE_PRECISION (TREE_TYPE (val));
+      tree ntype = TREE_TYPE (val);
+      unsigned int prec = TYPE_PRECISION (ntype);
+      wide_int mask = wide_int::zero (largest_bitsize, largest_precision);
+
+      /* Add asserts for NAME cmp CST and NAME being defined
+	 as NAME = (int) NAME2.  */
       unsigned int nprec = prec;
       enum tree_code rhs_code = ERROR_MARK;
 
@@ -4780,12 +4849,12 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 	      && tree_fits_uhwi_p (cst2)
 	      && INTEGRAL_TYPE_P (TREE_TYPE (name2))
 	      && IN_RANGE (tree_to_uhwi (cst2), 1, prec - 1)
-	      && prec <= HOST_BITS_PER_DOUBLE_INT
 	      && prec == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (val)))
 	      && live_on_edge (e, name2)
 	      && !has_single_use (name2))
 	    {
-	      mask = double_int::mask (tree_to_uhwi (cst2));
+	      mask = wide_int::mask (tree_to_uhwi (cst2), false, 
+				     largest_bitsize, largest_precision);
 	      val2 = fold_binary (LSHIFT_EXPR, TREE_TYPE (val), val, cst2);
 	    }
 	}
@@ -4808,20 +4877,26 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 		  val2 = fold_convert (type, val2);
 		}
 	      tmp = fold_build2 (MINUS_EXPR, TREE_TYPE (tmp), tmp, val2);
-	      new_val = double_int_to_tree (TREE_TYPE (tmp), mask);
+	      new_val = wide_int_to_infinite_tree (TREE_TYPE (tmp), mask,
+						   largest_precision);
 	      new_comp_code = comp_code == EQ_EXPR ? LE_EXPR : GT_EXPR;
 	    }
 	  else if (comp_code == LT_EXPR || comp_code == GE_EXPR)
 	    new_val = val2;
 	  else
 	    {
-	      double_int maxval
-		= double_int::max_value (prec, TYPE_UNSIGNED (TREE_TYPE (val)));
-	      mask |= tree_to_double_int (val2);
+	      wide_int::SignOp uns = TYPE_UNSIGNED (TREE_TYPE (val))
+		? wide_int::UNSIGNED : wide_int::SIGNED;
+		
+	      wide_int maxval = wide_int::max_value (TREE_TYPE (val))
+		.force_to_size (largest_bitsize, largest_precision, uns)
+		.ext (TYPE_PRECISION (TREE_TYPE (val)), wide_int::UNSIGNED);
+	      mask = tree_to_infinite_wide_int (val2) | mask;
 	      if (mask == maxval)
 		new_val = NULL_TREE;
 	      else
-		new_val = double_int_to_tree (TREE_TYPE (val2), mask);
+		new_val = wide_int_to_infinite_tree (TREE_TYPE (val2), mask,
+						     largest_precision);
 	    }
 
 	  if (new_val)
@@ -4867,13 +4942,13 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 	  else
 	    {
 	      cst2 = TYPE_MAX_VALUE (TREE_TYPE (val));
-	      nprec = TYPE_PRECISION (TREE_TYPE (name2));
+	      ntype = TREE_TYPE (name2);
+	      nprec = TYPE_PRECISION (ntype);
 	    }
 	  if (TREE_CODE (name2) == SSA_NAME
 	      && INTEGRAL_TYPE_P (TREE_TYPE (name2))
 	      && TREE_CODE (cst2) == INTEGER_CST
 	      && !integer_zerop (cst2)
-	      && nprec <= HOST_BITS_PER_DOUBLE_INT
 	      && (nprec > 1
 		  || TYPE_UNSIGNED (TREE_TYPE (val))))
 	    {
@@ -4896,17 +4971,19 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 	}
       if (names[0] || names[1])
 	{
-	  double_int minv, maxv = double_int_zero, valv, cst2v;
-	  double_int tem, sgnbit;
+	  wide_int minv, valv, cst2v;
+	  wide_int zero = wide_int::zero (largest_bitsize, largest_precision);
+	  wide_int maxv = zero;
+	  wide_int tem, sgnbit;
 	  bool valid_p = false, valn = false, cst2n = false;
 	  enum tree_code ccode = comp_code;
 
-	  valv = tree_to_double_int (val).zext (nprec);
-	  cst2v = tree_to_double_int (cst2).zext (nprec);
+	  valv = tree_to_infinite_wide_int (val).zext (nprec);
+	  cst2v = tree_to_infinite_wide_int (cst2).zext (nprec);
 	  if (!TYPE_UNSIGNED (TREE_TYPE (val)))
 	    {
-	      valn = valv.sext (nprec).is_negative ();
-	      cst2n = cst2v.sext (nprec).is_negative ();
+	      valn = valv.sext (nprec).neg_p ();
+	      cst2n = cst2v.sext (nprec).neg_p ();
 	    }
 	  /* If CST2 doesn't have most significant bit set,
 	     but VAL is negative, we have comparison like
@@ -4914,9 +4991,11 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 	  if (!cst2n && valn)
 	    ccode = ERROR_MARK;
 	  if (cst2n)
-	    sgnbit = double_int_one.llshift (nprec - 1, nprec).zext (nprec);
+	    sgnbit = wide_int::set_bit_in_zero (nprec - 1, 
+						largest_bitsize, 
+						largest_precision);
 	  else
-	    sgnbit = double_int_zero;
+	    sgnbit = zero;
 	  minv = valv & cst2v;
 	  switch (ccode)
 	    {
@@ -4925,34 +5004,35 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 		 (should be equal to VAL, otherwise we probably should
 		 have folded the comparison into false) and
 		 maximum unsigned value is VAL | ~CST2.  */
-	      maxv = valv | ~cst2v;
+	      maxv = valv.or_not (cst2v);
 	      maxv = maxv.zext (nprec);
 	      valid_p = true;
 	      break;
 	    case NE_EXPR:
-	      tem = valv | ~cst2v;
+	      tem = valv.or_not (cst2v);
 	      tem = tem.zext (nprec);
 	      /* If VAL is 0, handle (X & CST2) != 0 as (X & CST2) > 0U.  */
-	      if (valv.is_zero ())
+	      if (valv.zero_p ())
 		{
 		  cst2n = false;
-		  sgnbit = double_int_zero;
+		  sgnbit = zero;
 		  goto gt_expr;
 		}
 	      /* If (VAL | ~CST2) is all ones, handle it as
 		 (X & CST2) < VAL.  */
-	      if (tem == double_int::mask (nprec))
+	      if (tem == wide_int::mask (nprec, false, 
+					 largest_bitsize, largest_precision))
 		{
 		  cst2n = false;
 		  valn = false;
-		  sgnbit = double_int_zero;
+		  sgnbit = zero;
 		  goto lt_expr;
 		}
-	      if (!cst2n
-		  && cst2v.sext (nprec).is_negative ())
-		sgnbit
-		  = double_int_one.llshift (nprec - 1, nprec).zext (nprec);
-	      if (!sgnbit.is_zero ())
+	      if (!cst2n && cst2v.sext (nprec).neg_p ())
+		sgnbit = wide_int::set_bit_in_zero (nprec - 1, 
+						    largest_bitsize, 
+						    largest_precision);
+	      if (!sgnbit.zero_p ())
 		{
 		  if (valv == sgnbit)
 		    {
@@ -4960,13 +5040,15 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 		      valn = true;
 		      goto gt_expr;
 		    }
-		  if (tem == double_int::mask (nprec - 1))
+		  if (tem == wide_int::mask (nprec - 1, false, 
+					     largest_bitsize, 
+					     largest_precision))
 		    {
 		      cst2n = true;
 		      goto lt_expr;
 		    }
 		  if (!cst2n)
-		    sgnbit = double_int_zero;
+		    sgnbit = zero;
 		}
 	      break;
 	    case GE_EXPR:
@@ -4979,11 +5061,12 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 		{
 		  /* If (VAL & CST2) != VAL, X & CST2 can't be equal to
 		     VAL.  */
-		  minv = masked_increment (valv, cst2v, sgnbit, nprec);
+		  minv = masked_increment (valv, cst2v, sgnbit, ntype);
 		  if (minv == valv)
 		    break;
 		}
-	      maxv = double_int::mask (nprec - (cst2n ? 1 : 0));
+	      maxv = wide_int::mask (nprec - (cst2n ? 1 : 0), false,
+				     largest_bitsize, largest_precision);
 	      valid_p = true;
 	      break;
 	    case GT_EXPR:
@@ -4991,10 +5074,11 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 	      /* Find out smallest MINV where MINV > VAL
 		 && (MINV & CST2) == MINV, if any.  If VAL is signed and
 		 CST2 has MSB set, compute it biased by 1 << (nprec - 1).  */
-	      minv = masked_increment (valv, cst2v, sgnbit, nprec);
+	      minv = masked_increment (valv, cst2v, sgnbit, ntype);
 	      if (minv == valv)
 		break;
-	      maxv = double_int::mask (nprec - (cst2n ? 1 : 0));
+	      maxv = wide_int::mask (nprec - (cst2n ? 1 : 0), false,
+				     largest_bitsize, largest_precision);
 	      valid_p = true;
 	      break;
 	    case LE_EXPR:
@@ -5010,12 +5094,13 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 		maxv = valv;
 	      else
 		{
-		  maxv = masked_increment (valv, cst2v, sgnbit, nprec);
+		  maxv = masked_increment (valv, cst2v, sgnbit, ntype);
 		  if (maxv == valv)
 		    break;
-		  maxv -= double_int_one;
+		  maxv = maxv - wide_int::one (largest_bitsize, 
+					       largest_precision);
 		}
-	      maxv |= ~cst2v;
+	      maxv = maxv.or_not (cst2v);
 	      maxv = maxv.zext (nprec);
 	      minv = sgnbit;
 	      valid_p = true;
@@ -5038,12 +5123,13 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 		}
 	      else
 		{
-		  maxv = masked_increment (valv, cst2v, sgnbit, nprec);
+		  maxv = masked_increment (valv, cst2v, sgnbit, ntype);
 		  if (maxv == valv)
 		    break;
 		}
-	      maxv -= double_int_one;
-	      maxv |= ~cst2v;
+	      maxv = maxv - wide_int::one (largest_bitsize, 
+					   largest_precision);
+	      maxv = maxv.or_not (cst2v);
 	      maxv = maxv.zext (nprec);
 	      minv = sgnbit;
 	      valid_p = true;
@@ -5052,7 +5138,9 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 	      break;
 	    }
 	  if (valid_p
-	      && (maxv - minv).zext (nprec) != double_int::mask (nprec))
+	      && (maxv - minv).zext (nprec) 
+	        != wide_int::mask (nprec, false, 
+				   largest_bitsize, largest_precision))
 	    {
 	      tree tmp, new_val, type;
 	      int i;
@@ -5060,7 +5148,7 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 	      for (i = 0; i < 2; i++)
 		if (names[i])
 		  {
-		    double_int maxv2 = maxv;
+		    wide_int maxv2 = maxv;
 		    tmp = names[i];
 		    type = TREE_TYPE (names[i]);
 		    if (!TYPE_UNSIGNED (type))
@@ -5068,13 +5156,15 @@ register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
 			type = build_nonstandard_integer_type (nprec, 1);
 			tmp = build1 (NOP_EXPR, type, names[i]);
 		      }
-		    if (!minv.is_zero ())
+		    if (!minv.zero_p ())
 		      {
 			tmp = build2 (PLUS_EXPR, type, tmp,
-				      double_int_to_tree (type, -minv));
+				      wide_int_to_infinite_tree 
+				      (type, minv.neg (), largest_precision));
 			maxv2 = maxv - minv;
 		      }
-		    new_val = double_int_to_tree (type, maxv2);
+		    new_val = wide_int_to_infinite_tree (type, maxv2,
+							 largest_precision);
 
 		    if (dump_file)
 		      {
@@ -5994,7 +6084,7 @@ search_for_addr_array (tree t, location_t location)
     {
       tree tem = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
       tree low_bound, up_bound, el_sz;
-      double_int idx;
+      wide_int idx;
       if (TREE_CODE (TREE_TYPE (tem)) != ARRAY_TYPE
 	  || TREE_CODE (TREE_TYPE (TREE_TYPE (tem))) == ARRAY_TYPE
 	  || !TYPE_DOMAIN (TREE_TYPE (tem)))
@@ -6011,17 +6101,19 @@ search_for_addr_array (tree t, location_t location)
 	  || TREE_CODE (el_sz) != INTEGER_CST)
 	return;
 
-      idx = mem_ref_offset (t);
-      idx = idx.sdiv (tree_to_double_int (el_sz), TRUNC_DIV_EXPR);
-      if (idx.slt (double_int_zero))
+      idx = mem_ref_offset (t).force_to_size (largest_bitsize, 
+					      largest_precision,
+					      wide_int::SIGNED);
+      idx = idx.sdiv_trunc (tree_to_infinite_wide_int (el_sz));
+      if (idx.lts_p (0))
 	{
 	  warning_at (location, OPT_Warray_bounds,
 		      "array subscript is below array bounds");
 	  TREE_NO_WARNING (t) = 1;
 	}
-      else if (idx.sgt (tree_to_double_int (up_bound)
-			- tree_to_double_int (low_bound)
-			+ double_int_one))
+      else if (idx.gts_p (tree_to_infinite_wide_int (up_bound)
+			  - tree_to_infinite_wide_int (low_bound)
+			  + wide_int::one (largest_bitsize, largest_precision)))
 	{
 	  warning_at (location, OPT_Warray_bounds,
 		      "array subscript is above array bounds");
@@ -6188,6 +6280,78 @@ remove_range_assertions (void)
 }
 
 
+/* Return true if STMT is interesting for VRP and initialize
+   largest_bitsize and largest_precision.  */
+
+static void
+look_for_largest (gimple stmt)
+{
+  if (gimple_code (stmt) == GIMPLE_PHI)
+    {
+      tree res = gimple_phi_result (stmt);
+      tree type = TREE_TYPE (res);
+
+      if (!virtual_operand_p (res)
+	  && (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)))
+      {
+	largest_bitsize = MAX (largest_bitsize, 
+			       GET_MODE_BITSIZE (TYPE_MODE (type)));
+	largest_precision = MAX (largest_precision, TYPE_PRECISION (type));
+      }
+    }
+  else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
+    {
+      tree lhs = gimple_get_lhs (stmt);
+
+      /* In general, assignments with virtual operands are not useful
+	 for deriving ranges, with the obvious exception of calls to
+	 builtin functions.  */
+      if (lhs && TREE_CODE (lhs) == SSA_NAME
+	  && (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+	      || POINTER_TYPE_P (TREE_TYPE (lhs)))
+	  && ((is_gimple_call (stmt)
+	       && gimple_call_fndecl (stmt) != NULL_TREE
+	       && DECL_BUILT_IN (gimple_call_fndecl (stmt)))
+	      || !gimple_vuse (stmt)))
+	{
+	  tree type = TREE_TYPE (lhs);
+	  largest_bitsize = MAX (largest_bitsize, 
+				 GET_MODE_BITSIZE (TYPE_MODE (type)));
+	  largest_precision = MAX (largest_precision, TYPE_PRECISION (type));
+	}
+    }
+}
+
+
+/* Find the largest integer types.  */
+
+static void
+largest_initialize (void)
+{
+  basic_block bb;
+
+  largest_bitsize = GET_MODE_BITSIZE (word_mode);
+  largest_precision = GET_MODE_PRECISION (word_mode);
+
+  FOR_EACH_BB (bb)
+    {
+      gimple_stmt_iterator si;
+
+      for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
+        look_for_largest (gsi_stmt (si));
+
+      for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
+        look_for_largest (gsi_stmt (si));
+    }
+
+  /* We need to leave enough space so that we can see some bits above
+     the largest precision.  */
+  largest_bitsize *= 2;
+  largest_bitsize = MIN (largest_bitsize, MAX_BITSIZE_MODE_ANY_INT);
+  largest_precision *= 2;
+  largest_precision = MIN (largest_precision, MAX_BITSIZE_MODE_ANY_INT);
+}
+
 /* Return true if STMT is interesting for VRP.  */
 
 static bool
@@ -8256,9 +8420,9 @@ simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
   tree op = NULL_TREE;
   value_range_t vr0 = VR_INITIALIZER;
   value_range_t vr1 = VR_INITIALIZER;
-  double_int may_be_nonzero0, may_be_nonzero1;
-  double_int must_be_nonzero0, must_be_nonzero1;
-  double_int mask;
+  wide_int may_be_nonzero0, may_be_nonzero1;
+  wide_int must_be_nonzero0, must_be_nonzero1;
+  wide_int mask;
 
   if (TREE_CODE (op0) == SSA_NAME)
     vr0 = *(get_value_range (op0));
@@ -8283,13 +8447,13 @@ simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
     {
     case BIT_AND_EXPR:
       mask = may_be_nonzero0.and_not (must_be_nonzero1);
-      if (mask.is_zero ())
+      if (mask.zero_p ())
 	{
 	  op = op0;
 	  break;
 	}
       mask = may_be_nonzero1.and_not (must_be_nonzero0);
-      if (mask.is_zero ())
+      if (mask.zero_p ())
 	{
 	  op = op1;
 	  break;
@@ -8297,13 +8461,13 @@ simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
       break;
     case BIT_IOR_EXPR:
       mask = may_be_nonzero0.and_not (must_be_nonzero1);
-      if (mask.is_zero ())
+      if (mask.zero_p ())
 	{
 	  op = op1;
 	  break;
 	}
       mask = may_be_nonzero1.and_not (must_be_nonzero0);
-      if (mask.is_zero ())
+      if (mask.zero_p ())
 	{
 	  op = op0;
 	  break;
@@ -8573,15 +8737,18 @@ simplify_switch_using_ranges (gimple stmt)
 static bool
 simplify_conversion_using_ranges (gimple stmt)
 {
-  tree innerop, middleop, finaltype;
+  tree innerop, middleop;
+  tree middle_type, final_type;
   gimple def_stmt;
   value_range_t *innervr;
-  bool inner_unsigned_p, middle_unsigned_p, final_unsigned_p;
+  bool inner_unsigned_p;
   unsigned inner_prec, middle_prec, final_prec;
-  double_int innermin, innermed, innermax, middlemin, middlemed, middlemax;
+  wide_int innermin, innermed, innermax, middlemin, middlemed, middlemax;
+  tree inner_type;
+  wide_int::SignOp inner_uns;
 
-  finaltype = TREE_TYPE (gimple_assign_lhs (stmt));
-  if (!INTEGRAL_TYPE_P (finaltype))
+  final_type = TREE_TYPE (gimple_assign_lhs (stmt));
+  if (!INTEGRAL_TYPE_P (final_type))
     return false;
   middleop = gimple_assign_rhs1 (stmt);
   def_stmt = SSA_NAME_DEF_STMT (middleop);
@@ -8601,43 +8768,48 @@ simplify_conversion_using_ranges (gimple stmt)
 
   /* Simulate the conversion chain to check if the result is equal if
      the middle conversion is removed.  */
-  innermin = tree_to_double_int (innervr->min);
-  innermax = tree_to_double_int (innervr->max);
-
-  inner_prec = TYPE_PRECISION (TREE_TYPE (innerop));
-  middle_prec = TYPE_PRECISION (TREE_TYPE (middleop));
-  final_prec = TYPE_PRECISION (finaltype);
-
+  innermin = tree_to_infinite_wide_int (innervr->min);
+  innermax = tree_to_infinite_wide_int (innervr->max);
+
+  inner_type = TREE_TYPE (innerop);
+  inner_prec = TYPE_PRECISION (inner_type);
+  middle_type = TREE_TYPE (middleop);
+  middle_prec = TYPE_PRECISION (middle_type);
+  final_prec = TYPE_PRECISION (final_type);
+  
   /* If the first conversion is not injective, the second must not
      be widening.  */
-  if ((innermax - innermin).ugt (double_int::mask (middle_prec))
+  if ((innermax - innermin).gtu_p (wide_int::mask (middle_prec, false, 
+						   largest_bitsize,
+						   largest_precision))
       && middle_prec < final_prec)
     return false;
   /* We also want a medium value so that we can track the effect that
      narrowing conversions with sign change have.  */
   inner_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (innerop));
+  inner_uns = inner_unsigned_p ? wide_int::UNSIGNED : wide_int::SIGNED;
   if (inner_unsigned_p)
-    innermed = double_int::mask (inner_prec).lrshift (1, inner_prec);
+    innermed = wide_int::mask (inner_prec - 1, false, 
+			       largest_bitsize, largest_precision);
   else
-    innermed = double_int_zero;
-  if (innermin.cmp (innermed, inner_unsigned_p) >= 0
-      || innermed.cmp (innermax, inner_unsigned_p) >= 0)
+    innermed = wide_int::zero (largest_bitsize, largest_precision);
+
+  if ((!innermin.lt_p (innermed, inner_uns))
+      || !innermed.lt_p (innermax, inner_uns))
     innermed = innermin;
 
-  middle_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (middleop));
-  middlemin = innermin.ext (middle_prec, middle_unsigned_p);
-  middlemed = innermed.ext (middle_prec, middle_unsigned_p);
-  middlemax = innermax.ext (middle_prec, middle_unsigned_p);
+  middlemin = innermin.ext (middle_type);
+  middlemed = innermed.ext (middle_type);
+  middlemax = innermax.ext (middle_type);
 
   /* Require that the final conversion applied to both the original
      and the intermediate range produces the same result.  */
-  final_unsigned_p = TYPE_UNSIGNED (finaltype);
-  if (middlemin.ext (final_prec, final_unsigned_p)
-	 != innermin.ext (final_prec, final_unsigned_p)
-      || middlemed.ext (final_prec, final_unsigned_p)
-	 != innermed.ext (final_prec, final_unsigned_p)
-      || middlemax.ext (final_prec, final_unsigned_p)
-	 != innermax.ext (final_prec, final_unsigned_p))
+  if (middlemin.ext (final_type)
+      != innermin.ext (final_type)
+      || middlemed.ext (final_type)
+      != innermed.ext (final_type)
+      || middlemax.ext (final_type)
+      != innermax.ext (final_type))
     return false;
 
   gimple_assign_set_rhs1 (stmt, innerop);
@@ -8646,14 +8818,14 @@ simplify_conversion_using_ranges (gimple stmt)
 }
 
 /* Return whether the value range *VR fits in an integer type specified
-   by PRECISION and UNSIGNED_P.  */
+   by PRECISION.  The operand is assumed to be signed.  */
 
 static bool
-range_fits_type_p (value_range_t *vr, unsigned precision, bool unsigned_p)
+range_fits_type_p (value_range_t *vr, unsigned precision)
 {
   tree src_type;
   unsigned src_precision;
-  double_int tem;
+  wide_int tem;
 
   /* We can only handle integral and pointer types.  */
   src_type = TREE_TYPE (vr->min);
@@ -8665,7 +8837,7 @@ range_fits_type_p (value_range_t *vr, unsigned precision, bool unsigned_p)
   src_precision = TYPE_PRECISION (TREE_TYPE (vr->min));
   if (src_precision < precision
       || (src_precision == precision
-	  && TYPE_UNSIGNED (src_type) == unsigned_p))
+	  && !TYPE_UNSIGNED (src_type)))
     return true;
 
   /* Now we can only handle ranges with constant bounds.  */
@@ -8674,19 +8846,13 @@ range_fits_type_p (value_range_t *vr, unsigned precision, bool unsigned_p)
       || TREE_CODE (vr->max) != INTEGER_CST)
     return false;
 
-  /* For precision-preserving sign-changes the MSB of the double-int
-     has to be clear.  */
-  if (src_precision == precision
-      && (TREE_INT_CST_HIGH (vr->min) | TREE_INT_CST_HIGH (vr->max)) < 0)
-    return false;
-
   /* Then we can perform the conversion on both ends and compare
      the result for equality.  */
-  tem = tree_to_double_int (vr->min).ext (precision, unsigned_p);
-  if (tree_to_double_int (vr->min) != tem)
+  tem = tree_to_infinite_wide_int (vr->min).sext (precision);
+  if (tree_to_infinite_wide_int (vr->min) != tem)
     return false;
-  tem = tree_to_double_int (vr->max).ext (precision, unsigned_p);
-  if (tree_to_double_int (vr->max) != tem)
+  tem = tree_to_infinite_wide_int (vr->max).sext (precision);
+  if (tree_to_infinite_wide_int (vr->max) != tem)
     return false;
 
   return true;
@@ -8715,7 +8881,7 @@ simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
       && (can_float_p (fltmode, TYPE_MODE (TREE_TYPE (rhs1)), 0)
 	  != CODE_FOR_nothing)
       && range_fits_type_p (vr, GET_MODE_PRECISION
-			          (TYPE_MODE (TREE_TYPE (rhs1))), 0))
+			    (TYPE_MODE (TREE_TYPE (rhs1)))))
     mode = TYPE_MODE (TREE_TYPE (rhs1));
   /* If we can do the conversion in the current input mode do nothing.  */
   else if (can_float_p (fltmode, TYPE_MODE (TREE_TYPE (rhs1)),
@@ -8732,7 +8898,7 @@ simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
 	     or if the value-range does not fit in the signed type
 	     try with a wider mode.  */
 	  if (can_float_p (fltmode, mode, 0) != CODE_FOR_nothing
-	      && range_fits_type_p (vr, GET_MODE_PRECISION (mode), 0))
+	      && range_fits_type_p (vr, GET_MODE_PRECISION (mode)))
 	    break;
 
 	  mode = GET_MODE_WIDER_MODE (mode);
@@ -9152,6 +9318,7 @@ execute_vrp (void)
   loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
   rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
   scev_initialize ();
+  largest_initialize ();
 
   insert_range_assertions ();
 
diff --git a/gcc/tree.c b/gcc/tree.c
index 84f2cbc..1b11044 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -1074,15 +1074,27 @@ double_int_to_tree (tree type, double_int cst)
 tree
 wide_int_to_tree (tree type, const wide_int &cst)
 {
-  wide_int v;
+  wide_int v = cst.force_to_size ((const_tree)type);
+ 
+  return build_int_cst_wide (type, v.elt (0), v.elt (1));
+}
 
-  gcc_assert (cst.get_len () <= 2);
-  if (TYPE_UNSIGNED (type))
-    v = cst.zext (TYPE_PRECISION (type));
-  else
-    v = cst.sext (TYPE_PRECISION (type));
+/* Constructs tree in type TYPE from with value given by CST.
+   Signedness of CST is assumed to be the same as the signedness of
+   TYPE.  The number is represented in an infinite filed of PREC bits.
+   This number should be twice the sized of the largest integer mode
+   in the function being compiled.  */
 
-  return build_int_cst_wide (type, v.elt (0), v.elt (1));
+tree
+wide_int_to_infinite_tree (tree type, const wide_int &cst, unsigned int prec)
+{
+  wide_int::SignOp sgn = TYPE_UNSIGNED (type) 
+    ? wide_int::UNSIGNED : wide_int::SIGNED;
+  wide_int v = cst.ext (TYPE_PRECISION (type), sgn);
+  HOST_WIDE_INT e1 = (prec <= HOST_BITS_PER_WIDE_INT) 
+    ? v.elt (0) >> (HOST_BITS_PER_WIDE_INT - 1) : v.elt (1);
+
+  return build_int_cst_wide (type, v.elt (0), e1);
 }
 
 /* Return 0 or -1 depending on the sign of the cst.  */ 
@@ -1265,6 +1277,61 @@ force_fit_type_double (tree type, double_int cst, int overflowable,
   return double_int_to_tree (type, cst);
 }
 
+/* We force the wide_int CST to the range of the type TYPE by sign or
+   zero extending it.  OVERFLOWABLE indicates if we are interested in
+   overflow of the value, when >0 we are only interested in signed
+   overflow, for <0 we are interested in any overflow.  OVERFLOWED
+   indicates whether overflow has already occurred.  CONST_OVERFLOWED
+   indicates whether constant overflow has already occurred.  We force
+   T's value to be within range of T's type (by setting to 0 or 1 all
+   the bits outside the type's range).  We set TREE_OVERFLOWED if,
+        OVERFLOWED is nonzero,
+        or OVERFLOWABLE is >0 and signed overflow occurs
+        or OVERFLOWABLE is <0 and any overflow occurs
+   We return a new tree node for the extended wide_int.  The node
+   is shared if no overflow flags are set.  */
+
+
+tree
+force_fit_type_wide (tree type, const wide_int &cst, int overflowable,
+		     bool overflowed)
+{
+  /* Size types *are* sign extended.  */
+  bool sign_extended_type = !TYPE_UNSIGNED (type);
+
+  /* If we need to set overflow flags, return a new unshared node.  */
+  if (overflowed || !cst.fits_to_tree_p (type))
+    {
+      if (overflowed
+	  || overflowable < 0
+	  || (overflowable > 0 && sign_extended_type))
+	{
+#ifdef NEW_REP_FOR_INT_CST
+	  wide_int::SignOp uns = TYPE_UNSIGNED (type) 
+	    ? wide_int::UNSIGNED : wide_int::SIGNED;
+	  const wide_int &r = cst.ext (TYPE_PRECISION (type), uns);
+	  tree t = make_int_cst (r.get_len ());
+	  int i;
+
+	  for (i = 0; i < r.get_len (); ++i)
+	    TREE_INT_CST_ELT (t, i) = r.elt (i);
+#else
+	  tree t = make_node (INTEGER_CST);
+	  double_int d = double_int::from_pair (cst.elt (1), cst.elt(0));
+
+	  TREE_INT_CST (t) = d.ext (TYPE_PRECISION (type),
+					     !sign_extended_type);
+#endif
+	  TREE_TYPE (t) = type;
+	  TREE_OVERFLOW (t) = 1;
+	  return t;
+	}
+    }
+
+  /* Else build a shared node.  */
+  return wide_int_to_tree (type, cst);
+}
+
 /* These are the hash table functions for the hash table of INTEGER_CST
    nodes of a sizetype.  */
 
@@ -1293,6 +1360,7 @@ int_cst_hash_eq (const void *x, const void *y)
 	  && TREE_INT_CST_LOW (xt) == TREE_INT_CST_LOW (yt));
 }
 
+
 /* Create an INT_CST node of TYPE and value HI:LOW.
    The returned node is always shared.  For small integers we use a
    per-type vector cache, for larger ones we use a single hash table.  */
@@ -4130,12 +4198,21 @@ build_simple_mem_ref_loc (location_t loc, tree ptr)
 /* Return the constant offset of a MEM_REF or TARGET_MEM_REF tree T.  */
 
 double_int
-mem_ref_offset (const_tree t)
+mem_ref_offset_as_double (const_tree t)
 {
   tree toff = TREE_OPERAND (t, 1);
   return tree_to_double_int (toff).sext (TYPE_PRECISION (TREE_TYPE (toff)));
 }
 
+/* Return the constant offset of a MEM_REF or TARGET_MEM_REF tree T.  */
+
+wide_int
+mem_ref_offset (const_tree t)
+{
+  tree toff = TREE_OPERAND (t, 1);
+  return wide_int::from_tree (toff);
+}
+
 /* Return the pointer-type relevant for TBAA purposes from the
    gimple memory reference tree T.  This is the type to be used for
    the offset operand of MEM_REF or TARGET_MEM_REF replacements of T.  */
diff --git a/gcc/tree.h b/gcc/tree.h
index f5497cd..74348d1 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5835,7 +5835,7 @@ extern tree fold_indirect_ref_loc (location_t, tree);
 extern tree build_simple_mem_ref_loc (location_t, tree);
 #define build_simple_mem_ref(T)\
 	build_simple_mem_ref_loc (UNKNOWN_LOCATION, T)
-extern double_int mem_ref_offset (const_tree);
+extern double_int mem_ref_offset_as_double (const_tree);
 extern tree reference_alias_ptr_type (const_tree);
 extern tree build_invariant_address (tree, tree, HOST_WIDE_INT);
 extern tree constant_boolean_node (bool, tree);
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 0666fcb..ee477f0 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -2583,7 +2583,7 @@ decode_addr_const (tree exp, struct addr_const *value)
       else if (TREE_CODE (target) == MEM_REF
 	       && TREE_CODE (TREE_OPERAND (target, 0)) == ADDR_EXPR)
 	{
-	  offset += mem_ref_offset (target).low;
+	  offset += mem_ref_offset_as_double (target).low;
 	  target = TREE_OPERAND (TREE_OPERAND (target, 0), 0);
 	}
       else if (TREE_CODE (target) == INDIRECT_REF

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 8th patch - tree-vrp.c
  2012-11-01 22:13                                                                         ` patch to fix constant math - 8th patch - tree-vrp.c Kenneth Zadeck
@ 2012-11-01 22:28                                                                           ` Marc Glisse
  2012-11-01 22:35                                                                             ` Kenneth Zadeck
  2012-11-01 22:33                                                                           ` patch to fix constant math - 4th patch - wide-int.[ch] refresh Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Marc Glisse @ 2012-11-01 22:28 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford

On Thu, 1 Nov 2012, Kenneth Zadeck wrote:

> This patch converts tree-vpn to use wide-int.   In doing so it gets rid of 
> all restrictions that this pass currently has on the target or source word 
> size.
>
> The pass's reliance on a finite "infinite precision" representation has been 
> preserved.  It first scans the function being compiled to determine the 
> largest type that needs to be represented within that function and then it 
> uses some multiple of that size as it's definition of infinite.
>
> I am currently using 4 for this value.   However marc glisse claims that this 
> may be due to a bug and that the value should be 2. This is something that 
> has to be investigated further.   This could easily be my mistake or some 
> other issue that has crept into the pass.  The value of 2 or 4 is easily 
> changed in largest_initialize.    The only truly non mechanical 
> transformation is in the code that multiplies two ranges.   This code uses 
> the wide-int multiply full functions rather than using pairs of double-ints.

(I didn't look at the patch (yet))

Er, no, I didn't claim that using 4 was wrong, I think it is good because 
it makes things easier. I only claimed that the current implementation 
jumps through enough hoops to make do with 2.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - wide-int.[ch] refresh
  2012-11-01 22:13                                                                         ` patch to fix constant math - 8th patch - tree-vrp.c Kenneth Zadeck
  2012-11-01 22:28                                                                           ` Marc Glisse
@ 2012-11-01 22:33                                                                           ` Kenneth Zadeck
  2012-11-01 22:36                                                                             ` Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-11-01 22:33 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Marc Glisse

This patch refreshes wide-int.[ch].   Most of the changes are bug fixes 
that were fixed for tree-vrp.c in patch 8.

There are two significant differences:

1) There are now constructors to override the precision and bitsize that 
are normally taken from the type.  These are used to perform the finite 
"infinite precision" that is required by the tree-vrp.c pass.   The 
bitsize and precision passed in are the ones necessary to compile the 
current function.

2) The signed and unsigned extension functions have changed a lot. The 
ones with the name ext do an extension but the result always has the 
bitsize and precision of this.  the functions that are named 
force_to_size, now return results based on the precision and bitsize 
passed in after doing the proper extension.

The second change is in line with comments made by richi and others.

kenny


^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 8th patch - tree-vrp.c
  2012-11-01 22:28                                                                           ` Marc Glisse
@ 2012-11-01 22:35                                                                             ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-11-01 22:35 UTC (permalink / raw)
  To: Marc Glisse
  Cc: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford

either way, this needs to be investigated.  it could just be my bad.
On 11/01/2012 06:28 PM, Marc Glisse wrote:
> On Thu, 1 Nov 2012, Kenneth Zadeck wrote:
>
>> This patch converts tree-vpn to use wide-int.   In doing so it gets 
>> rid of all restrictions that this pass currently has on the target or 
>> source word size.
>>
>> The pass's reliance on a finite "infinite precision" representation 
>> has been preserved.  It first scans the function being compiled to 
>> determine the largest type that needs to be represented within that 
>> function and then it uses some multiple of that size as it's 
>> definition of infinite.
>>
>> I am currently using 4 for this value.   However marc glisse claims 
>> that this may be due to a bug and that the value should be 2. This is 
>> something that has to be investigated further. This could easily be 
>> my mistake or some other issue that has crept into the pass.  The 
>> value of 2 or 4 is easily changed in largest_initialize.    The only 
>> truly non mechanical transformation is in the code that multiplies 
>> two ranges.   This code uses the wide-int multiply full functions 
>> rather than using pairs of double-ints.
>
> (I didn't look at the patch (yet))
>
> Er, no, I didn't claim that using 4 was wrong, I think it is good 
> because it makes things easier. I only claimed that the current 
> implementation jumps through enough hoops to make do with 2.
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - wide-int.[ch] refresh
  2012-11-01 22:33                                                                           ` patch to fix constant math - 4th patch - wide-int.[ch] refresh Kenneth Zadeck
@ 2012-11-01 22:36                                                                             ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-11-01 22:36 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Marc Glisse

[-- Attachment #1: Type: text/plain, Size: 983 bytes --]

this time with the patch and changelog
On 11/01/2012 06:33 PM, Kenneth Zadeck wrote:
> This patch refreshes wide-int.[ch].   Most of the changes are bug 
> fixes that were fixed for tree-vrp.c in patch 8.
>
> There are two significant differences:
>
> 1) There are now constructors to override the precision and bitsize 
> that are normally taken from the type.  These are used to perform the 
> finite "infinite precision" that is required by the tree-vrp.c pass.   
> The bitsize and precision passed in are the ones necessary to compile 
> the current function.
>
> 2) The signed and unsigned extension functions have changed a lot. The 
> ones with the name ext do an extension but the result always has the 
> bitsize and precision of this.  the functions that are named 
> force_to_size, now return results based on the precision and bitsize 
> passed in after doing the proper extension.
>
> The second change is in line with comments made by richi and others.
>
> kenny
>
>


[-- Attachment #2: p4-2.clog --]
[-- Type: text/plain, Size: 190 bytes --]

2012-11-1  Kenneth Zadeck <zadeck@naturalbridge.com>

	* wide-int.c: New file containing implementation of wide_int class.
	* wide-int.h: New file containing public spec for wide_int class.

[-- Attachment #3: p4-2.diff --]
[-- Type: text/x-patch, Size: 153217 bytes --]

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 77ba4df..af89420 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -841,7 +841,7 @@ COMMON_TARGET_DEF_H = common/common-target-def.h \
 RTL_BASE_H = coretypes.h rtl.h rtl.def $(MACHMODE_H) reg-notes.def \
   insn-notes.def $(INPUT_H) $(REAL_H) statistics.h $(VEC_H) \
   $(FIXED_VALUE_H) alias.h $(HASHTAB_H)
-FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h
+FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h wide-int.h
 RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h vecir.h
 RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H)
 READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
@@ -853,7 +853,7 @@ INTERNAL_FN_H = internal-fn.h $(INTERNAL_FN_DEF)
 TREE_H = coretypes.h tree.h all-tree.def tree.def c-family/c-common.def \
 	$(lang_tree_files) $(MACHMODE_H) tree-check.h $(BUILTINS_DEF) \
 	$(INPUT_H) statistics.h $(VEC_H) treestruct.def $(HASHTAB_H) \
-	double-int.h alias.h $(SYMTAB_H) $(FLAGS_H) vecir.h \
+	double-int.h wide-int.h alias.h $(SYMTAB_H) $(FLAGS_H) vecir.h \
 	$(REAL_H) $(FIXED_VALUE_H)
 REGSET_H = regset.h $(BITMAP_H) hard-reg-set.h
 BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) \
@@ -1433,6 +1433,7 @@ OBJS = \
 	varpool.o \
 	vmsdbgout.o \
 	web.o \
+	wide-int.o \
 	xcoffout.o \
 	$(out_object_file) \
 	$(EXTRA_OBJS) \
@@ -2640,6 +2641,7 @@ targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
    tree-ssa-alias.h $(TREE_FLOW_H)
 common/common-targhooks.o : common/common-targhooks.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(INPUT_H) $(TM_H) $(COMMON_TARGET_H) common/common-targhooks.h
+wide-int.o: wide-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
 
 bversion.h: s-bversion; @true
 s-bversion: BASE-VER
@@ -3834,15 +3836,16 @@ CFLAGS-gengtype-parse.o += -DGENERATOR_FILE
 build/gengtype-parse.o: $(BCONFIG_H)
 
 gengtype-state.o build/gengtype-state.o: gengtype-state.c $(SYSTEM_H) \
-  gengtype.h errors.h double-int.h version.h $(HASHTAB_H) $(OBSTACK_H) \
-  $(XREGEX_H)
+  gengtype.h errors.h double-int.h wide-int.h version.h $(HASHTAB_H)    \
+  $(OBSTACK_H) $(XREGEX_H)
 gengtype-state.o: $(CONFIG_H)
 CFLAGS-gengtype-state.o += -DGENERATOR_FILE
 build/gengtype-state.o: $(BCONFIG_H)
+wide-int.h: $(GTM_H) insn-modes.h
 
 gengtype.o build/gengtype.o : gengtype.c $(SYSTEM_H) gengtype.h 	\
-  rtl.def insn-notes.def errors.h double-int.h version.h $(HASHTAB_H) \
-  $(OBSTACK_H) $(XREGEX_H)
+  rtl.def insn-notes.def errors.h double-int.h wide-int.h version.h     \
+  $(HASHTAB_H) $(OBSTACK_H) $(XREGEX_H)
 gengtype.o: $(CONFIG_H)
 CFLAGS-gengtype.o += -DGENERATOR_FILE
 build/gengtype.o: $(BCONFIG_H)
diff --git a/gcc/alias.c b/gcc/alias.c
index 0c6a744..9e67823 100644
diff --git a/gcc/wide-int.c b/gcc/wide-int.c
new file mode 100644
index 0000000..9a63db3
--- /dev/null
+++ b/gcc/wide-int.c
@@ -0,0 +1,4404 @@
+/* Operations with very long integers.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hwint.h"
+#include "wide-int.h"
+#include "rtl.h"
+#include "tree.h"
+#include "dumpfile.h"
+
+#define DEBUG_WIDE_INT
+#ifdef DEBUG_WIDE_INT
+  /* Debugging routines.  */
+  static void debug_vw  (const char* fmt, int r, const wide_int& o0);
+  static void debug_vwh (const char* fmt, int r, const wide_int &o0,
+			 HOST_WIDE_INT o1);
+  static void debug_vww (const char* fmt, int r, const wide_int &o0,
+			 const wide_int &o1);
+  static void debug_whh (const char* fmt, const wide_int &r,
+			 HOST_WIDE_INT o1, HOST_WIDE_INT o2);
+  static void debug_wv (const char* fmt, const wide_int &r, int v0);
+  static void debug_wvv (const char* fmt, const wide_int &r, int v0,
+			 int v1);
+  static void debug_wvvv (const char* fmt, const wide_int &r, int v0,
+			  int v1, int v2);
+  static void debug_wvww (const char* fmt, const wide_int &r, int v0,
+			  const wide_int &o0, const wide_int &o1);
+  static void debug_wwv (const char* fmt, const wide_int &r,
+			 const wide_int &o0, int v0);
+  static void debug_wwvvs (const char* fmt, const wide_int &r, 
+			   const wide_int &o0, 
+			   int v0, int v1, const char *s);
+  static void debug_wwwvv (const char* fmt, const wide_int &r,
+			   const wide_int &o0, const wide_int &o1,
+			   int v0, int v1);
+  static void debug_ww (const char* fmt, const wide_int &r,
+			const wide_int &o0);
+  static void debug_www (const char* fmt, const wide_int &r,
+			 const wide_int &o0, const wide_int &o1);
+  static void debug_wwww (const char* fmt, const wide_int &r,
+			  const wide_int &o0, const wide_int &o1, 
+			  const wide_int &o2);
+#endif
+// using wide_int::;
+
+/* Debugging routines.  */
+
+/* This is the maximal size of the buffer needed for dump.  */
+const int MAX = 4 * (MAX_BITSIZE_MODE_ANY_INT / 4
+		     + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
+
+/*
+ * Internal utilities.
+ */
+
+/* Quantities to deal with values that hold half of a wide int.  Used
+   in multiply and divide.  */
+#define HALF_INT_MASK (((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1)
+
+#define BLOCK_OF(TARGET) ((TARGET) / HOST_BITS_PER_WIDE_INT)
+#define BLOCKS_NEEDED(PREC) \
+  (((PREC) + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+
+/*
+ * Conversion routines in and out of wide-int.
+ */
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, unsigned int bitsize, unsigned int precision)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    op0 = sext_hwi (op0, precision);
+
+  result.val[0] = op0;
+  result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+	       "wide_int::from_shwi", result.dump (buf0), op0);
+    }
+#endif
+
+  return result;
+}
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  The overflow bit are set if the number was too
+   large to fit in the mode.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, unsigned int bitsize,
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT t = sext_hwi (op0, precision);
+      if (t != op0)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+  result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+	       "wide_int::from_shwi", result.dump (buf0), op0);
+    }
+#endif
+
+  return result;
+}
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0,
+		     unsigned int bitsize, unsigned int precision)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    op0 = zext_hwi (op0, precision);
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && precision > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+	       "wide_int::from_uhwi", result.dump (buf0), op0);
+    }
+#endif
+
+  return result;
+}
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  The overflow bit are set if the number was too
+   large to fit in the mode.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, unsigned int bitsize, 
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT t = zext_hwi (op0, precision);
+      if (t != op0)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && precision > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      char buf0[MAX];
+      fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
+	       "wide_int::from_uhwi", result.dump (buf0), op0);
+    }
+#endif
+
+  return result;
+}
+
+/* Convert a double int into a wide int with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::from_double_int (double_int di, unsigned int bs, unsigned int prec)
+{
+  HOST_WIDE_INT op = di.low;
+  wide_int result;
+
+  result.bitsize = bs;
+  result.precision = prec;
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result.val[0] = sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    result.val[1] = sext_hwi (di.high, prec);
+	  else
+	    result.val[1] = di.high;
+	}
+    }
+
+  if (result.len == 2)
+    result.canonize ();
+
+  return result;
+}
+
+/* Convert a integer cst into a wide int.  */
+
+wide_int
+wide_int::from_tree (const_tree tcst)
+{
+#ifdef NEW_REP_FOR_INT_CST
+  /* This is the code once the tree level is converted.  */
+  wide_int result;
+  int i;
+
+  tree type = TREE_TYPE (tcst);
+
+  result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  result.precision = TYPE_PRECISION (type);
+  result.len = TREE_INT_CST_LEN (tcst);
+  for (i = 0; i < result.len; i++)
+    result.val[i] = TREE_INT_CST_ELT (tcst, i);
+
+  return result;
+#else
+  wide_int result;
+  tree type = TREE_TYPE (tcst);
+  unsigned int prec = TYPE_PRECISION (type);
+  HOST_WIDE_INT op = TREE_INT_CST_LOW (tcst);
+
+  result.precision = prec;
+  result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    if (TYPE_UNSIGNED (type))
+      result.val[0] = zext_hwi (op, prec);
+    else
+      result.val[0] = sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    {
+	      op = TREE_INT_CST_HIGH (tcst);
+	      if (TYPE_UNSIGNED (type))
+		result.val[1] = zext_hwi (op, prec);
+	      else
+		result.val[1] = sext_hwi (op, prec);
+	    }
+	  else
+	    result.val[1] = TREE_INT_CST_HIGH (tcst);
+	}
+    }
+  
+  if (result.len == 2)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      debug_whh ("wide_int:: %s = from_tree ("HOST_WIDE_INT_PRINT_HEX" "HOST_WIDE_INT_PRINT_HEX")\n",
+		 result, TREE_INT_CST_HIGH (tcst), TREE_INT_CST_LOW (tcst));
+    }
+#endif
+
+  return result;
+#endif
+}
+
+/* Convert a integer cst into a wide int expanded to BITSIZE and
+   PRECISION.  This call is used by tree passes like vrp that expect
+   that the math is done in an infinite precision style.  BITSIZE and
+   PRECISION are generally determined to be twice the largest type
+   seen in the function.  */
+
+wide_int
+wide_int::from_tree_as_infinite_precision (const_tree tcst, 
+					   unsigned int bitsize, 
+					   unsigned int precision)
+{
+  /* The plan here is to extend the value in the cst, using signed or
+     unsigned based on the type, from the precision in the type to
+     PRECISION and then canonize from there.  */
+  wide_int result;
+  tree type = TREE_TYPE (tcst);
+  unsigned int prec = TYPE_PRECISION (type);
+
+
+#ifdef NEW_REP_FOR_INT_CST
+  /* This is the code once the tree level is converted.  */
+  int i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  result.len = TREE_INT_CST_LEN (tcst);
+  for (i = 0; i < result.len; i++)
+    result.val[i] = TREE_INT_CST_ELT (tcst, i);
+
+  if (TYPE_UNSIGNED (type))
+    result = result.zext (prec);
+  else
+    result = result.sext (prec);
+
+#else
+  HOST_WIDE_INT op = TREE_INT_CST_LOW (tcst);
+
+  gcc_assert (prec <= precision);
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  result.len = 1;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result.val[0] = TYPE_UNSIGNED (type) 
+      ? zext_hwi (op, prec) : sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    {
+	      op = TREE_INT_CST_HIGH (tcst);
+	      prec -= HOST_BITS_PER_WIDE_INT;
+	      result.val[1] = TYPE_UNSIGNED (type) 
+		? zext_hwi (op, prec) : sext_hwi (op, prec);
+	      result.len = 2;
+	    }
+	  else
+	    {
+	      result.val[1] = TREE_INT_CST_HIGH (tcst);
+	      if (TYPE_UNSIGNED (type) && result.val[1] < 0)
+		{
+		  result.val[2] = 0;
+		  result.len = 2;
+		}
+	      else
+		result.len = 2;
+	    }
+	}
+      else
+	if (TYPE_UNSIGNED (type) && result.val[0] < 0)
+	  {
+	    result.val[1] = 0;
+	    result.len = 2;
+	  }
+    }
+
+#endif
+
+  return result;
+}
+
+/* Extract a constant integer from the X of type MODE.  The bits of
+   the integer are returned.  */
+
+wide_int
+wide_int::from_rtx (const_rtx x, enum machine_mode mode)
+{
+  wide_int result;
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  gcc_assert (mode != VOIDmode);
+
+  result.bitsize = GET_MODE_BITSIZE (mode);
+  result.precision = prec;
+
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+      if ((prec & (HOST_BITS_PER_WIDE_INT - 1)) != 0)
+	result.val[0] = sext_hwi (INTVAL (x), prec);
+      else
+	result.val[0] = INTVAL (x);
+      result.len = 1;
+      break;
+
+#if TARGET_SUPPORTS_WIDE_INT
+    case CONST_WIDE_INT:
+      {
+	int i;
+	result.len = CONST_WIDE_INT_NUNITS (x);
+	
+	for (i = 0; i < result.len; i++)
+	  result.val[i] = CONST_WIDE_INT_ELT (x, i);
+      }
+      break;
+#else
+    case CONST_DOUBLE:
+      result.len = 2;
+      result.val[0] = CONST_DOUBLE_LOW (x);
+      result.val[1] = CONST_DOUBLE_HIGH (x);
+      result.canonize ();
+      break;
+#endif
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return result;
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = sext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS is too large for
+   the mode's precision, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi () const
+{
+  return to_shwi (precision);
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = zext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS is too large for
+   the mode's precision, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi () const
+{
+  return to_uhwi (precision);
+}
+
+/*
+ * Largest and smallest values in a mode.
+ */
+
+/* Produce the largest number that is represented in BITSIZE of
+   PREC. SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (unsigned int bitsize, unsigned int prec, SignOp sgn)
+{
+  wide_int result;
+  
+  result.bitsize = bitsize;
+  result.precision = prec;
+
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned max is just all ones, for which the compressed
+	 rep is just a single HWI.  */ 
+      result.len = 1;
+      result.val[0] = (HOST_WIDE_INT)-1;
+    }
+  else
+    {
+      /* The signed max is all ones except the top bit.  This must be
+	 explicitly represented.  */
+      int i;
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      int shift = (small_prec == 0) 
+	? HOST_BITS_PER_WIDE_INT - 1 : small_prec - 1;
+
+      result.len = BLOCKS_NEEDED (prec);
+      for (i = 0; i < result.len - 1; i++)
+	result.val[i] = (HOST_WIDE_INT)-1;
+
+      result.val[result.len - 1] = ((HOST_WIDE_INT)1 << shift) - 1;
+    }
+  
+  return result;
+}
+
+/* Produce the largest number that is represented in MODE. The
+   bitsize and precision are taken from mode.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (enum machine_mode mode, SignOp sgn)
+{
+  return max_value (GET_MODE_BITSIZE (mode), GET_MODE_PRECISION (mode), sgn);
+}
+
+/* Produce the largest number that is represented in TYPE. The
+   bitsize and precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::max_value (const_tree type)
+{
+  return max_value (GET_MODE_BITSIZE (TYPE_MODE (type)), 
+		    TYPE_PRECISION (type), 
+		    TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+/* Produce the smallest number that is represented in BITSIZE of
+   PREC. SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::min_value (unsigned int bitsize, unsigned int prec, SignOp sgn)
+{
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned min is just all zeros, for which the compressed
+	 rep is just a single HWI.  */ 
+      wide_int result;
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = prec;
+      result.val[0] = 0;
+      return result;
+    }
+  else
+    {
+      /* The signed min is all zeros except the top bit.  This must be
+	 explicitly represented.  */
+      return set_bit_in_zero (prec - 1, bitsize, prec);
+    }
+}
+
+/* Produce the smallest number that is represented in MODE. The
+   bitsize and precision are taken from mode.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::min_value (enum machine_mode mode, SignOp sgn)
+{
+  return min_value (GET_MODE_BITSIZE (mode), GET_MODE_PRECISION (mode), sgn);
+}
+
+/* Produce the smallest number that is represented in TYPE. The
+   bitsize and precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::min_value (const_tree type)
+{
+  return min_value (GET_MODE_BITSIZE (TYPE_MODE (type)), 
+		    TYPE_PRECISION (type), 
+		    TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+/*
+ * Public utilities.
+ */
+
+/* Check the upper HOST_WIDE_INTs of src to see if the length can be
+   shortened.  An upper HOST_WIDE_INT is unnecessary if it is all ones
+   or zeros and the top bit of the next lower word matches.
+
+   This function may change the representation of THIS, but does not
+   change the value that THIS represents.  It does not sign extend in
+   the case that the size of the mode is less than
+   HOST_BITS_PER_WIDE_INT.  */
+
+void
+wide_int::canonize ()
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT top;
+  int i;
+
+  if (len > blocks_needed)
+    len = blocks_needed;
+
+  /* Clean up the top bits for any mode that is not a multiple of a HWI.  */
+  if (len == blocks_needed && small_prec)
+    val[len - 1] = sext_hwi (val[len - 1], small_prec);
+
+  if (len == 1)
+    return;
+
+  top = val[len - 1];
+  if (top != 0 && top != (HOST_WIDE_INT)-1)
+    return;
+
+  /* At this point we know that the top is either 0 or -1.  Find the
+     first block that is not a copy of this.  */
+  for (i = len - 2; i >= 0; i--)
+    {
+      HOST_WIDE_INT x = val[i];
+      if (x != top)
+	{
+	  if (x >> (HOST_BITS_PER_WIDE_INT - 1) == top)
+	    {
+	      len = i + 1;
+	      return;
+	    }
+
+	  /* We need an extra block because the top bit block i does
+	     not match the extension.  */
+	  len = i + 2;
+	  return;
+	}
+    }
+
+  /* The number is 0 or -1.  */
+  len = 1;
+}
+
+/* Copy THIS replacing the bitsize with BS and precision with PREC.
+   It can do any of truncation, extension or copying.  */
+
+wide_int
+wide_int::force_to_size (unsigned int bs, unsigned int prec, SignOp sgn) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (prec);
+  int i;
+
+  result.bitsize = bs;
+  result.precision = prec;
+  result.len = blocks_needed < len ? blocks_needed : len;
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+
+  if (prec >= precision) 
+    {
+      /* Expanding */
+      int small_precision = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+      if (sgn == UNSIGNED)
+	{
+	  if (len == BLOCKS_NEEDED (precision)
+	      && len < blocks_needed
+	      && small_precision == 0
+	      && result.val[result.len - 1] < 0)
+	    /* We need to put the 0 block on top to keep the value
+	       from being sign extended.  */ 
+	    result.val[result.len++] = 0;
+
+	  /* We are unsigned and the current precision is not on an
+	     even block and that block is explicitly represented.
+	     Then we have to do an explicit zext of the top block. */
+	  else if (small_precision && blocks_needed == len)
+	    result.val[blocks_needed-1]
+	      = zext_hwi (result.val[blocks_needed-1], small_precision);
+	}
+    }
+  else
+    {
+      /* Truncating.  */
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      /* The only weird case we need to look at here is when we are
+         truncating withing the top block.  We need to make sure that
+         everything in the block above the new precision is sign
+         extended.  Note that this is independent of the SGN.  This is
+         just to stay canonical.  */
+      if (small_prec && (blocks_needed == len))
+	result.val[blocks_needed-1]
+	  = sext_hwi (result.val[blocks_needed-1], small_prec);
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwvvs ("wide_int:: %s = force_to_size (%s, bs = %d, prec = %d %s)\n", 
+		 result, *this, bs, prec, sgn==UNSIGNED ? "U" : "S");
+#endif
+
+  return result;
+}
+
+/*
+ * public printing routines.
+ */
+
+/* Try to print the signed self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_DEC, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decs (buf);
+  fputs (buf, file);
+}
+
+/* Try to print the unsigned self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decu (buf);
+  fputs (buf, file);
+}
+
+void 
+wide_int::print_hex (char *buf) const
+{
+  int i = len;
+
+  if (zero_p ())
+    sprintf (buf, "0x");
+  else
+    {
+      if (neg_p ())
+	{
+	  int j;
+	  /* If the number is negative, we may need to pad value with
+	     0xFFF...  because the leading elements may be missing and
+	     we do not print a '-' with hex.  */
+	  for (j = BLOCKS_NEEDED (precision); j > i; j--)
+	    buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, (HOST_WIDE_INT) -1);
+	    
+	}
+      else
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_HEX, val [--i]);
+      while (-- i >= 0)
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, val [i]);
+    }
+}
+
+/* Print one big hex number to FILE.  Note that some assemblers may not
+   accept this for large modes.  */
+void 
+wide_int::print_hex (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_hex (buf);
+  fputs (buf, file);
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently singed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+bool
+wide_int::operator == (const wide_int &op1) const
+{
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = true;
+      goto ex;
+    }
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << precision) - 1;
+      result = (val[0] & mask) == (op1.val[0] & mask);
+      goto ex;
+    }
+
+  while (l0 > l1)
+    if (val[l0--] != op1.sign_mask ())
+      {
+	result = false;
+	goto ex;
+      }
+
+  while (l1 > l0)
+    if (op1.val[l1--] != sign_mask ())
+      {
+	result = false;
+	goto ex;
+      }
+
+  while (l0 >= 0)
+    if (val[l0--] != op1.val[l1--])
+      {
+	result = false;
+	goto ex;
+      }
+
+  result = true;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wideint:: %d = (%s == %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS > OP1 using signed comparisons.  */
+
+bool
+wide_int::gts_p (const HOST_WIDE_INT op1) const
+{
+  bool result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] > sext_hwi (op1, precision);
+      goto ex;
+    }
+  
+  result = !neg_p ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int:: %d = (%s gts_p 0x"HOST_WIDE_INT_PRINT_HEX")\n", 
+	       result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS > OP1 using unsigned comparisons.  */
+
+bool
+wide_int::gtu_p (const unsigned HOST_WIDE_INT op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  if (precision < HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1, precision);
+
+      result = x0 > x1;
+    }
+  else
+    result = true;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int:: %d = (%s gtu_p 0x"HOST_WIDE_INT_PRINT_HEX")\n", 
+	       result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p (const HOST_WIDE_INT op1) const
+{
+  bool result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] < sext_hwi (op1, precision);
+      goto ex;
+    }
+  
+  result = neg_p ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int:: %d = (%s lts_p 0x"HOST_WIDE_INT_PRINT_HEX")\n", 
+	       result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p (const wide_int &op1) const
+{
+  int l;
+  int result;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  int blocks_needed = BLOCKS_NEEDED (precision);
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] < op1.val[0];
+      goto ex;
+    }
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == len ? val [blocks_needed - 1] : sign_mask ();
+  s1 = blocks_needed == op1.len ? op1.val [blocks_needed - 1] : op1.sign_mask ();
+  if (s0 < s1)
+    {
+      result = true;
+      goto ex;
+    }
+  if (s0 > s1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  l = MAX (len, op1.len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < len ? val [l] : sign_mask ();
+      u1 = l < op1.len ? op1.val [l] : op1.sign_mask ();
+
+      if (u0 < u1)
+	{
+	  result = true;
+	  goto ex;
+	}
+      if (u0 > u1)
+	{
+	  result = false;
+	  goto ex;
+	}
+      l--;
+    }
+
+  result = false;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s lts_p %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+int
+wide_int::cmps (const wide_int &op1) const
+{
+  int l;
+  int result;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  int blocks_needed = BLOCKS_NEEDED (precision);
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = 0;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      if (val[0] < op1.val[0])
+	{
+	  result = -1;
+	  goto ex;
+	}
+      if (val[0] > op1.val[0])
+	{
+	  result = 1;
+	  goto ex;
+	}
+    }
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == len ? val [blocks_needed - 1] : sign_mask ();
+  s1 = blocks_needed == op1.len ? op1.val [blocks_needed - 1] : op1.sign_mask ();
+  if (s0 < s1)
+    {
+      result = -1;
+      goto ex;
+    }
+  if (s0 > s1)
+    {
+      result = 1;
+      goto ex;
+    }
+
+  l = MAX (len, op1.len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < len ? val [l] : sign_mask ();
+      u1 = l < op1.len ? op1.val [l] : op1.sign_mask ();
+
+      if (u0 < u1)
+	{
+	  result = -1;
+	  goto ex;
+	}
+      if (u0 > u1)
+	{
+	  result = 1;
+	  goto ex;
+	}
+      l--;
+    }
+
+  result = 0;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s cmps %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p (const unsigned HOST_WIDE_INT op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  if (precision < HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1, precision);
+
+      result = x0 < x1;
+    }
+  else
+    result = false;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int:: %d = (%s ltu_p 0x"HOST_WIDE_INT_PRINT_HEX")\n", 
+	       result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1.val[0], precision);
+
+      result = x0 < x1;
+      goto ex;
+    }
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1.sign_mask ();
+      if (x0 < x1)
+	{
+	  result = true;
+	  goto ex;
+	}
+      if (x0 > x1)
+	{
+	  result = false;
+	  goto ex;
+	}
+    }
+
+  while (l1 > l0)
+    {
+      x0 = sign_mask ();
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	{
+	  result = true;
+	  goto ex;
+	}
+      if (x0 > x1)
+	{
+	  result = false;
+	  goto ex;
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	{
+	  result = true;
+	  goto ex;
+	}
+      if (x0 > x1)
+	{
+	  result = false;
+	  goto ex;
+	}
+    }
+
+  result = false;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s ltu_p %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+int
+wide_int::cmpu (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  int result;
+
+  if (this == &op1)
+    {
+      result = 0;
+      goto ex;
+    }
+
+  gcc_assert (precision == op1.precision);
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1.val[0], precision);
+
+      if (x0 < x1)
+	result = -1;
+      else if (x0 == x1)
+	result = 0;
+      else
+	result = 1;
+      goto ex;
+    }
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1.sign_mask ();
+      if (x0 < x1)
+	{
+	  result = -1;
+	  goto ex;
+	}
+      else if (x0 > x1)
+	{
+	  result = 1;
+	  goto ex;
+	}
+    }
+
+  while (l1 > l0)
+    {
+      x0 = sign_mask ();
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	{
+	  result = -1;
+	  goto ex;
+	}
+      if (x0 > x1)
+	{
+	  result = 1;
+	  goto ex;
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	{
+	  result = -1;
+	  goto ex;
+	}
+      if (x0 > x1)
+	{
+	  result = 1;
+	  goto ex;
+	}
+    }
+
+  result = 0;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s cmpu %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p (unsigned int prec) const
+{
+  int i;
+  HOST_WIDE_INT x;
+  int small_prec;
+  bool result;
+
+  if (BLOCKS_NEEDED (prec) != len)
+    {
+      result = false;
+      goto ex;
+    }
+
+  for (i=0; i < len - 1; i++)
+    if (val[i] != 0)
+      {
+	result = false;
+	goto ex;
+      }
+
+  x = val[len - 1];
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec)
+    x = x << (HOST_BITS_PER_WIDE_INT - small_prec);
+
+  result = x == ((HOST_WIDE_INT)1) << (HOST_BITS_PER_WIDE_INT - 1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = only_sign_bit_p (%s)\n", result, *this);
+#endif
+
+  return result;
+}
+
+bool
+wide_int::only_sign_bit_p () const
+{
+  return only_sign_bit_p (precision);
+}
+
+/* Returns true if THIS fits into range of TYPE.  Signedness of OP0 is
+   assumed to be the same as the signedness of TYPE.  */
+
+bool
+wide_int::fits_to_tree_p (const_tree type) const
+{
+  int type_prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return fits_u_p (type_prec);
+  else
+    return fits_s_p (type_prec);
+}
+
+/* Returns true of THIS fits in the unsigned range of precision.  */
+
+bool
+wide_int::fits_s_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == sext (prec);
+}
+
+
+/* Returns true if THIS fits into range of TYPE.  */
+
+bool
+wide_int::fits_u_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == zext (prec);
+}
+
+/*
+ * Extension.
+ */
+
+/* Sign extend THIS starting at OFFSET.  The bitsize and precision of
+   the result are the same as THIS.  */
+
+wide_int
+wide_int::sext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.bitsize = bitsize;
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = sext_hwi (val[0], offset);
+      else
+	/* If offset is greater or equal to precision there is nothing
+	   to do since the internal rep is already sign extended.  */
+	result.val[0] = val[0];
+
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, bitsize, precision);
+      
+      /* Now we can do the real sign extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      if (off)
+	{
+	  int block = BLOCK_OF (offset);
+	  result.val[block] = sext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      /* We never need an extra element for sign extended values.  */
+    }    
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s sext %d)\n", result, *this, offset);
+#endif
+
+  return result;
+}
+
+/* Zero extend THIS starting at OFFSET.  The bitsize and precision of
+   the result are the same as THIS.  */
+
+wide_int
+wide_int::zext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+  int block;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.bitsize = bitsize;
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = zext_hwi (val[0], offset);
+      else if (offset == precision)
+	result.val[0] = val[0];
+	/* If offset was greater than the precision we need to zero
+	   extend from the old precision since the internal rep was
+	   equivalent to sign extended.  */
+      else
+	result.val[0] = zext_hwi (val[0], precision);
+	
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, bitsize, precision);
+
+      /* Now we can do the real zero extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      block = BLOCK_OF (offset);
+      if (off)
+	{
+	  result.val[block] = zext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      else
+	/* See if we need an extra zero element to satisfy the
+	   compression rule.  */
+	if (val[block - 1] < 0 && offset < precision)
+	  {
+	    result.val[block] = 0;
+	    result.len += 1;
+	  }
+    }
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s zext %d)\n", result, *this, offset);
+#endif
+
+  return result;
+}
+
+/*
+ * Masking, inserting, shifting, rotating.
+ */
+
+/* Return a value with a one bit inserted in THIS at BITPOS.  */
+
+wide_int
+wide_int::set_bit (unsigned int bitpos) const
+{
+  wide_int result;
+  int i, j;
+
+  if (bitpos >= precision)
+    result = force_to_size (bitsize, precision, UNSIGNED);
+  else
+    {
+      result = decompress (bitpos, bitsize, precision);
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s set_bit %d)\n", result, *this, bitpos);
+#endif
+
+  return result;
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with BITSIZE
+   and PRECISION.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, 
+			   unsigned int bitsize, unsigned int prec)
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (bitpos + 1);
+  int i, j;
+
+  result.bitsize = bitsize;
+  result.precision = prec;
+  if (bitpos >= prec)
+    {
+      result.len = 1;
+      result.val[0] = 0;
+    }
+  else
+    {
+      result.len = blocks_needed;
+      for (i = 0; i < blocks_needed; i++)
+	result.val[i] = 0;
+      
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wv ("wide_int:: %s = set_bit_in_zero (%d)\n", result, bitpos);
+#endif
+
+  return result;
+}
+
+/* Insert WIDTH bits from OP0 into THIS starting at START.  */
+
+wide_int
+wide_int::insert (const wide_int &op0, unsigned int start, 
+		  unsigned int width) const
+{
+  wide_int result;
+  wide_int mask;
+  wide_int tmp;
+
+  if (start + width >= precision) 
+    width = precision - start;
+
+  mask = shifted_mask (start, width, false, bitsize, precision);
+  tmp = op0.lshift (start, NONE, bitsize, precision);
+  result = tmp & mask;
+
+  tmp = and_not (mask);
+  result = result | tmp;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwwvv ("wide_int:: %s = (%s insert start = %d width = %d)\n", 
+		 result, *this, op0, start, width);
+#endif
+
+  return result;
+}
+
+/* bswap THIS.  */
+
+wide_int
+wide_int::bswap () const
+{
+  wide_int result;
+  int i, s;
+  int end;
+  int len = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT mask = sign_mask ();
+
+  /* This is not a well defined operation if the precision is not a
+     multiple of 8.  */
+  gcc_assert ((precision & 0x7) == 0);
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < len; i++)
+    result.val[0] = mask;
+
+  /* Only swap the bytes that are not the padding.  */
+  if ((precision & (HOST_BITS_PER_WIDE_INT - 1))
+      && (this->len == len))
+    end = precision;
+  else
+    end = this->len * HOST_BITS_PER_WIDE_INT;
+
+  for (s = 0; s < end; s += 8)
+    {
+      unsigned int d = precision - s - 8;
+      unsigned HOST_WIDE_INT byte;
+
+      int block = s / HOST_BITS_PER_WIDE_INT;
+      int offset = s & (HOST_BITS_PER_WIDE_INT - 1);
+
+      byte = (val[block] >> offset) & 0xff;
+
+      block = d / HOST_BITS_PER_WIDE_INT;
+      offset = d & (HOST_BITS_PER_WIDE_INT - 1);
+
+      result.val[block] &= ((((HOST_WIDE_INT)1 << offset) + 8)
+			    - ((HOST_WIDE_INT)1 << offset));
+      result.val[block] |= byte << offset;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = bswap (%s)\n", result, *this);
+#endif
+
+  return result;
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with BITSIZE and
+   PREC. */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, 
+		unsigned int bitsize, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  int shift;
+
+  gcc_assert (width < 2 * MAX_BITSIZE_MODE_ANY_INT);
+  gcc_assert (prec <= 2 * MAX_BITSIZE_MODE_ANY_INT);
+
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (bitsize, prec);
+      else
+	result = wide_int::zero (bitsize, prec);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wvv ("wide_int:: %s = mask (%d, negate = %d)\n", result, width, negate);
+#endif
+      return result;
+    }
+
+  result.bitsize = bitsize;
+  result.precision = prec;
+
+  while (i < width / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = width & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      HOST_WIDE_INT last = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~last : last;
+    }
+  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvv ("wide_int:: %s = mask (%d, negate = %d)\n", result, width, negate);
+#endif
+
+  return result;
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  */
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate,
+			unsigned int bitsize, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  unsigned int shift;
+  unsigned int end = start + width;
+  HOST_WIDE_INT block;
+
+  if (start + width > prec)
+    width = prec - start;
+ 
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (bitsize, prec);
+      else
+	result = wide_int::zero (bitsize, prec);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wvvv 
+	  ("wide_int:: %s = shifted_mask (start = %d width = %d negate = %d)\n", 
+	   result, start, width, negate);
+#endif
+      return result;
+    }
+
+  result.bitsize = bitsize;
+  result.precision = prec;
+
+  while (i < start / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? (HOST_WIDE_INT)-1 : 0;
+
+  shift = start & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift)
+    {
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      shift = (end) & (HOST_BITS_PER_WIDE_INT - 1);
+      if (shift)
+	{
+	  /* case 000111000 */
+	  block = (((HOST_WIDE_INT)1) << shift) - block - 1;
+	  result.val[i++] = negate ? ~block : block;
+	  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_wvvv 
+	      ("wide_int:: %s = shifted_mask (start = %d width = %d negate = %d)\n", 
+	       result, start, width, negate);
+#endif
+	  return result;
+	}
+      else
+	/* ...111000 */
+	result.val[i++] = negate ? block : ~block;
+    }
+
+  while (i < end / HOST_BITS_PER_WIDE_INT)
+    /* 1111111 */
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = end & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      /* 000011111 */
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~block : block;
+    }
+
+  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvvv 
+      ("wide_int:: %s = shifted_mask (start = %d width = %d negate = %d)\n", 
+       result, start, width, negate);
+#endif
+
+  return result;
+}
+
+
+/*
+ * logical operations.
+ */
+
+/* Return THIS & OP1.  */
+
+wide_int
+wide_int::operator & (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s & %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Return THIS & ~OP1.  */
+
+wide_int
+wide_int::and_not (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & ~op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s and_not %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+wide_int
+wide_int::operator | (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s | %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Return the logical negation (bitwise complement) of THIS.  */
+
+wide_int
+wide_int::operator ~ () const
+{
+  wide_int result;
+  int l0 = len - 1;
+
+  result.len = len;
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = ~val[l0];
+      l0--;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = (~ %s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Return THIS | ~OP1.  */
+
+wide_int
+wide_int::or_not (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | ~op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s or_not %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Return the exclusive ior (xor) of THIS and OP1.  */
+
+wide_int
+wide_int::operator ^ (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  while (l0 > l1)
+    {
+      result.val[l0] = val[l0] ^ op1.sign_mask ();
+      l0--;
+    }
+
+  while (l1 > l0)
+    {
+      result.val[l1] = sign_mask () ^ op1.val[l1];
+      l1--;
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] ^ op1.val[l0];
+      l0--;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s ^ %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/*
+ * math
+ */
+
+/* Absolute value of THIS.  */
+
+wide_int
+wide_int::abs () const
+{
+  if (sign_mask ())
+    return neg ();
+
+  wide_int result = force_to_size (bitsize, precision, SIGNED);
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = abs (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Add of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::operator + (const wide_int &op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      o1 = op1.val[0];
+      result.val[0] = sext_hwi (o0 + o1, precision);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s + %s)\n", result, *this, op1);
+#endif
+      return result;
+    }
+
+  result.len = len > op1.len ? len : op1.len;
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1.len ? (unsigned HOST_WIDE_INT)op1.val[i] : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      /* If the carry is 1, then we need another word.  If the carry
+	 is 0, we only need another word if the top bit is 1.  */
+      if (carry == 1 || (HOST_WIDE_INT)x < 0)
+	/* Check for signed overflow.  */
+	{
+	  result.val[result.len] = mask0 + mask1 + carry;
+	  result.len++;
+	}
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s + %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Add of OP0 and OP1 with overflow checking.  If the result overflows
+   within the precision, set OVERFLOW.  OVERFLOW is assumed to be
+   sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::add_overflow (const wide_int *op0, const wide_int *op1,
+			wide_int::SignOp sgn, bool *overflow)
+{
+  wide_int result;
+  const wide_int *tmp;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned int prec = op0->precision;
+  int i, small_prec;
+
+  result.precision = op0->precision;
+  result.bitsize = op0->bitsize;
+
+  /* Put the longer one first.  */
+  if (op0->len > op1->len)
+    {
+      tmp = op0;
+      op0 = op1;
+      op1 = tmp;
+    }
+
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < op0->len; i++)
+    {
+      o0 = op0->val[i];
+      o1 = op1->val[i];
+      x = o0 + o1 + carry;
+      result.elt_ref (i) = x;
+      carry = x < o0;
+    }
+
+  /* Uncompress the rest.  */
+  if (op0->len < op1->len)
+    {
+      unsigned HOST_WIDE_INT mask = op1->sign_mask ();
+      for (i = op0->len; i < op1->len; i++)
+	{
+	  o0 = op0->val[i];
+	  o1 = mask;
+	  x = o0 + o1 + carry;
+	  result.val[i] = x;
+	  carry = x < o0;
+	}
+    }
+
+  if (op0->len * HOST_BITS_PER_WIDE_INT < prec)
+    {
+      /* If the carry is 1, then we need another word.  If the carry
+	 is 0, we only need another word if the top bit is 1.  */
+      if (carry == 1 || (HOST_WIDE_INT)x < 0)
+	/* Check for signed overflow.  */
+	{
+	  result.val[result.len] = carry;
+	  result.len++;
+	}
+    }
+
+  result.set_len (op0->len);
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (sgn == wide_int::SIGNED)
+	{
+	  if (((x ^ o0) & (x ^ o1)) >> (HOST_BITS_PER_WIDE_INT - 1))
+	    *overflow = true;
+	}
+      else if (carry)
+	{
+	  if ((~o0) < o1)
+	    *overflow = true;
+	}
+      else
+	{
+	  if ((~o0) <= o1)
+	    *overflow = true;
+	}
+    }
+  else
+    {
+      /* Overflow in this case is easy since we can see bits beyond
+	 the precision.  If the value computed is not the sign
+	 extended value, then we have overflow.  */
+      unsigned HOST_WIDE_INT y;
+
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  Then the rest of the code just works.  */
+	  o0 = zext_hwi (o0, small_prec);
+	  o1 = zext_hwi (o1, small_prec);
+	  x = o0 + o1 + carry;
+	}
+      /* Short integers and modes with weird precisions.  */
+      y = sext_hwi (x, small_prec);
+      result.len = op1->len;
+      if (BLOCKS_NEEDED (prec) == result.len && x != y)
+	*overflow = true;
+      /* Then put the sign extended form back because that is the
+	 canonical form.  */
+      result.val[result.len - 1] = y;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvww ("wide_int:: %s %d = (%s +O %s)\n", 
+	       result, *overflow, *op0, *op1);
+#endif
+  return result;
+}
+
+/* Add this and X.  If overflow occurs, set OVERFLOW.  */
+
+wide_int
+wide_int::add (const wide_int &x, SignOp sgn, bool *overflow) const
+{
+  return add_overflow (this, &x, sgn, overflow);
+}
+
+/* Count leading zeros of THIS but only looking at the bits in the
+   smallest HWI of size mode.  */
+
+wide_int
+wide_int::clz (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (clz (), bs, prec);
+}
+
+/* Count leading zeros of THIS.  */
+
+int
+wide_int::clz () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_vw ("wide_int:: %d = clz (%s)\n", count, *this);
+#endif
+      return count;
+    }
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = clz_hwi (v) - (HOST_BITS_PER_WIDE_INT - small_prec);
+      start = len - 2;
+      if (v != 0)
+	{
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_vw ("wide_int:: %d = clz (%s)\n", count, *this);
+#endif
+	  return count;
+	}
+    }
+  else
+    {
+      count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = elt (i);
+      count += clz_hwi (v);
+      if (v != 0)
+	break;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = clz (%s)\n", count, *this);
+#endif
+  return count;
+}
+
+wide_int
+wide_int::clrsb (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (clrsb (), bs, prec);
+}
+
+/* Count the number of redundant leading bits of THIS.  Return result
+   as a HOST_WIDE_INT.  There is a wrapper to convert this into a
+   wide_int.  */
+
+int
+wide_int::clrsb () const
+{
+  if (neg_p ())
+    return operator ~ ().clz () - 1;
+
+  return clz () - 1;
+}
+
+wide_int
+wide_int::ctz (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (ctz (), bs, prec);
+}
+
+/* Count zeros of THIS.  Return result as a HOST_WIDE_INT.  There is a
+   wrapper to convert this into a wide_int.  */
+
+int
+wide_int::ctz () const
+{
+  int i;
+  unsigned int count = 0;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int end;
+  bool more_to_do;
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_vw ("wide_int:: %d = ctz (%s)\n", count, *this);
+#endif
+      return count;
+    }
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      end = len - 1;
+      more_to_do = true;
+    }
+  else
+    {
+      end = len;
+      more_to_do = false;
+    }
+
+  for (i = 0; i < end; i++)
+    {
+      v = val[i];
+      count += ctz_hwi (v);
+      if (v != 0)
+	{
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_vw ("wide_int:: %d = ctz (%s)\n", count, *this);
+#endif
+	  return count;
+	}
+    }
+
+  if (more_to_do)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = ctz_hwi (v);
+      /* The top word was all zeros so we have to cut it back to prec,
+	 because we are counting some of the zeros above the
+	 interesting part.  */
+      if (count > precision)
+	count = precision;
+    }
+  else
+    /* Skip over the blocks that are not represented.  They must be
+       all zeros at this point.  */
+    count = precision;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = ctz (%s)\n", count, *this);
+#endif
+  return count;
+}
+
+/* ffs of THIS.  */
+
+wide_int
+wide_int::ffs () const
+{
+  HOST_WIDE_INT count = ctz ();
+  if (count == precision)
+    count = 0;
+  else
+    count += 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = ffs (%s)\n", count, *this);
+#endif
+  return wide_int::from_shwi (count, word_mode);
+}
+
+/* Subroutines of the multiplication and division operations.  Unpack
+   the first IN_LEN HOST_WIDE_INTs in INPUT into 2 * IN_LEN
+   HOST_HALF_WIDE_INTs of RESULT.  The rest of RESULT is filled by
+   uncompressing the top bit of INPUT[IN_LEN - 1].  */
+
+static void
+wi_unpack (unsigned HOST_HALF_WIDE_INT *result, 
+	   const unsigned HOST_WIDE_INT *input,
+	   int in_len, int out_len)
+{
+  int i;
+  int j = 0;
+  HOST_WIDE_INT mask;
+
+  for (i = 0; i <in_len; i++)
+    {
+      result[j++] = input[i];
+      result[j++] = input[i] >> HOST_BITS_PER_HALF_WIDE_INT;
+    }
+  mask = ((HOST_WIDE_INT)input[in_len - 1]) >> (HOST_BITS_PER_WIDE_INT - 1);
+  mask &= HALF_INT_MASK;
+
+  /* Smear the sign bit.  */
+  while (j < out_len)
+    result[j++] = mask;
+}
+
+/* The inverse of wi_unpack.  IN_LEN is the the number of input
+   blocks.  The number of output blocks will be half this amount.  */
+
+static void
+wi_pack (unsigned HOST_WIDE_INT *result, 
+	 const unsigned HOST_HALF_WIDE_INT *input, 
+	 int in_len)
+{
+  int i = 0;
+  int j = 0;
+
+  while (i < in_len - 2)
+    {
+      result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+	| ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+      i += 2;
+    }
+
+  /* Handle the case where in_len is odd.   For this we zero extend.  */
+  if (i & 1)
+    result[j++] = (unsigned HOST_WIDE_INT)input[i];
+  else
+    result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+      | ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+}
+
+/* Return an integer that is the exact log2 of THIS.  */
+
+int
+wide_int::exact_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  HOST_WIDE_INT count;
+  HOST_WIDE_INT result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec < HOST_BITS_PER_WIDE_INT)
+	v = sext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = ::exact_log2 (v);
+      goto ex;
+    }
+
+  count = ctz ();
+  if (clz () + count + 1 == precision)
+    {
+      result = count;
+      goto ex;
+    }
+
+  result = -1;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = exact_log2 (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Return an integer that is the floor log2 of THIS.  */
+
+int
+wide_int::floor_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  HOST_WIDE_INT result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec < HOST_BITS_PER_WIDE_INT)
+	v = sext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = ::floor_log2 (v);
+      goto ex;
+    }
+
+  result = precision - 1 - clz ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = floor_log2 (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+
+/* Multiply Op1 by Op2.  If HIGH is set, only the upper half of the
+   result is returned.  If FULL is set, the entire result is returned
+   in a mode that is twice the width of the inputs.  However, that
+   mode needs to exist if the value is to be usable.  Clients that use
+   FULL need to check for this.
+
+   If HIGH or FULL are not setm throw away the upper half after the check
+   is made to see if it overflows.  Unfortunately there is no better
+   way to check for overflow than to do this.  OVERFLOW is assumed to
+   be sticky so it should be initialized.  SGN controls the signess
+   and is used to check overflow or if HIGH or FULL is set.  */
+
+static wide_int
+mul_internal (bool high, bool full, 
+	      const wide_int *op1, const wide_int *op2,
+	      wide_int::SignOp sgn,  bool *overflow, bool needs_overflow)
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1, k, t;
+  unsigned int i;
+  unsigned int j;
+  unsigned int prec = op1->get_precision ();
+  unsigned int blocks_needed = BLOCKS_NEEDED (prec);
+  unsigned int half_blocks_needed = blocks_needed * 2;
+  /* The sizes here are scaled to support a 2x largest mode by 2x
+     largest mode yielding a 4x largest mode result.  This is what is
+     needed by vpn.  */
+
+  unsigned HOST_HALF_WIDE_INT 
+    u[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT 
+    v[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  /* The '2' in 'R' is because we are internally doing a full
+     multiply.  */
+  unsigned HOST_HALF_WIDE_INT 
+    r[2 * 2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1;
+
+  result.set_bitsize (op1->get_bitsize ());
+  result.set_precision (op1->get_precision ());
+
+  if (high || full || needs_overflow)
+    {
+      /* If we need to check for overflow, we can only do half wide
+	 multiplies quickly because we need to look at the top bits to
+	 check for the overflow.  */
+      if (prec <= HOST_BITS_PER_HALF_WIDE_INT)
+	{
+	  HOST_WIDE_INT t, r;
+	  result.set_len (1);
+	  o0 = op1->elt (0);
+	  o1 = op2->elt (0);
+	  r = o0 * o1;
+	  /* Signed shift down will leave 0 or -1 if there was no
+	     overflow for signed or 0 for unsigned.  */
+	  t = r >> (HOST_BITS_PER_HALF_WIDE_INT - 1);
+	  if (needs_overflow)
+	    {
+	      if (sgn == wide_int::SIGNED)
+		{
+		  if (t != (HOST_WIDE_INT)-1 && t != 0)
+		    *overflow = true;
+		}
+	      else
+		{
+		  if (t != 0)
+		    *overflow = true;
+		}
+	    }
+	  if (full)
+	    {
+	      result.elt_ref (0) = sext_hwi (r, prec * 2);
+	      result.set_bitsize (op1->get_bitsize () * 2);
+	      result.set_precision (op1->get_precision () * 2);
+	    }
+	  else if (high)
+	    result.elt_ref (0) = r >> prec;
+	  else
+	    result.elt_ref (0) = sext_hwi (r, prec);
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_wvww ("wide_int:: %s %d = (%s *O %s)\n", 
+			result, *overflow, *op1, *op2);
+#endif
+	  return result;
+	}
+    }
+  else
+    {
+      if (prec <= HOST_BITS_PER_WIDE_INT)
+	{
+	  result.set_len (1);
+	  o0 = op1->elt (0);
+	  o1 = op2->elt (0);
+	  result.elt_ref (0) = sext_hwi (o0 * o1, prec);
+	  
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+#endif
+	  return result;
+	}
+    }
+
+  wi_unpack (u, &op1->uelt_ref (0), op1->get_len (), half_blocks_needed);
+  wi_unpack (v, &op2->uelt_ref (0), op2->get_len (), half_blocks_needed);
+
+  /* The 2 is for a full mult.  */
+  memset (r, 0, half_blocks_needed * 2 * HOST_BITS_PER_HALF_WIDE_INT / BITS_PER_UNIT);
+
+  for (j = 0; j < half_blocks_needed; j++)
+    {
+      k = 0;
+      for (i = 0; i < half_blocks_needed; i++)
+	{
+	  t = ((unsigned HOST_WIDE_INT)u[i] * (unsigned HOST_WIDE_INT)v[j]
+	       + r[i + j] + k);
+	  r[i + j] = t & HALF_INT_MASK;
+	  k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	}
+      r[j + half_blocks_needed] = k;
+    }
+
+  /* We did unsigned math above.  For signed we must adjust the
+     product (assuming we need to see that).  */
+  if (sgn == wide_int::SIGNED && (full || high || needs_overflow))
+    {
+      unsigned HOST_WIDE_INT b;
+      if ((*op1).neg_p ())
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)v[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+      if ((*op2).neg_p ())
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)u[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+    }
+
+  if (needs_overflow)
+    {
+      HOST_WIDE_INT top;
+
+      /* For unsigned, overflow is true if any of the top bits are set.
+	 For signed, overflow is true if any of the top bits are not equal
+	 to the sign bit.  */
+      if (sgn == wide_int::UNSIGNED)
+	top = 0;
+      else
+	{
+	  top = r[(half_blocks_needed) - 1];
+	  top = ((top << (HOST_BITS_PER_WIDE_INT / 2))
+		 >> (HOST_BITS_PER_WIDE_INT - 1));
+	  top &= mask;
+	}
+      
+      for (i = half_blocks_needed; i < half_blocks_needed * 2; i++)
+	if (((HOST_WIDE_INT)(r[i] & mask)) != top)
+	  *overflow = true; 
+    }
+
+  if (full)
+    {
+      /* compute [2prec] <- [prec] * [prec] */
+      wi_pack (&result.uelt_ref (0), r, 2 * half_blocks_needed);
+      result.set_len (blocks_needed * 2);
+      result.set_bitsize (op1->get_bitsize () * 2);
+      result.set_precision (op1->get_precision () * 2);
+    }
+  else if (high)
+    {
+      /* compute [prec] <- ([prec] * [prec]) >> [prec] */
+      wi_pack (&result.uelt_ref (blocks_needed >> 1), r, half_blocks_needed);
+      result.set_len (blocks_needed);
+    }
+  else
+    {
+      /* compute [prec] <- ([prec] * [prec]) && ((1 << [prec]) - 1) */
+      wi_pack (&result.uelt_ref (0), r, half_blocks_needed);
+      result.set_len (blocks_needed);
+    }
+      
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvww ("wide_int:: %s %d = (%s *O %s)\n", 
+		result, *overflow, *op1, *op2);
+#endif
+  return result;
+}
+
+/* Multiply THIS and OP1.  The result is the same precision as the
+   operands, so there is no reason for signed or unsigned
+   versions.  */
+
+wide_int
+wide_int::operator * (const wide_int &op1) const
+{
+  bool overflow = false;
+
+  return mul_internal (false, false, this, &op1, UNSIGNED, &overflow, false);
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.
+   OVERFLOW is set true if the result overflows.  */
+
+wide_int 
+wide_int::mul (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  return mul_internal (false, false, this, &op1, sgn, overflow, true);
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.  The
+   result is twice the precision as the operands.  The signess is
+   specified with SGN.  */
+
+wide_int
+wide_int::mul_full (const wide_int &op1, SignOp sgn) const
+{
+  bool overflow = false;
+
+  return mul_internal (false, true, this, &op1, sgn, &overflow, false);
+}
+
+/* Multiply THIS and OP1 and return the high part of that result.  The
+   signess is specified with SGN.  The result is the same precision as
+   the operands.  The mode is the same mode as the operands.  The
+   signess is specified with y.  */
+
+wide_int
+wide_int::mul_high (const wide_int &op1, SignOp sgn) const
+{
+  bool overflow = false;
+
+  return mul_internal (true, false, this, &op1, sgn, &overflow, false);
+}
+
+/* Negate THIS.  */
+
+wide_int
+wide_int::neg () const
+{
+  wide_int z = wide_int::from_shwi (0, bitsize, precision);
+  return z - *this;
+}
+
+/* Compute the parity of THIS.  */
+
+wide_int
+wide_int::parity (unsigned int bs, unsigned int prec) const
+{
+  int count = popcount ();
+  return wide_int::from_shwi (count & 1, bs, prec);
+}
+
+/* Compute the population count of THIS producing a number with
+   BITSIZE and PREC.  */
+
+wide_int
+wide_int::popcount (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (popcount (), bs, prec);
+}
+
+/* Compute the population count of THIS.  */
+
+int
+wide_int::popcount () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = popcount_hwi (v);
+      start = len - 2;
+    }
+  else
+    {
+      if (sign_mask ())
+	count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      else
+	count = 0;
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = val[i];
+      count += popcount_hwi (v);
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = popcount (%s)\n", count, *this);
+#endif
+  return count;
+}
+
+/* Subtract of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::operator - (const wide_int &op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the borrow in of the first element at 1.  */
+  unsigned HOST_WIDE_INT borrow = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      o0 = val[0];
+      o1 = op1.val[0];
+      result.val[0] = sext_hwi (o0 - o1, precision);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s - %s)\n", result, *this, op1);
+#endif
+      return result;
+    }
+
+  result.len = len > op1.len ? len : op1.len;
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1.len ? (unsigned HOST_WIDE_INT)op1.val[i] : mask1;
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      borrow = o0 < o1;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      /* If the borrow is 1, then we need another word.  If the borrow
+	 is 0, we only need another word if the top bit is 1.  */
+      if (borrow == 1
+	  || (x >> (HOST_BITS_PER_WIDE_INT - 1) == 1))
+	{
+	  /* Check for signed overflow.  */
+	  result.val[result.len] = mask0 - mask1 - borrow;
+	  result.len++;
+	}
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s - %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Subtract of THIS and OP1 with overflow checking.  If the result
+   overflows within the precision, set OVERFLOW.  OVERFLOW is assumed
+   to be sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::sub_overflow (const wide_int *op0, const wide_int *op1, 
+			wide_int::SignOp sgn, bool *overflow)
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the borrow in of the first element at 1.  */
+  unsigned HOST_WIDE_INT borrow = 0;
+  int i, small_prec;
+
+  result.bitsize = op0->bitsize;
+  result.precision = op0->precision;
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < op0->len; i++)
+    {
+      o0 = op0->val[i];
+      o1 = op1->val[i];
+      x = o0 - o1 - borrow;
+      result.elt_ref (i) = x;
+      borrow = o0 < o1;
+    }
+
+  /* Uncompress the rest.  */
+  if (op1->len < op1->len)
+    {
+      unsigned HOST_WIDE_INT mask = op1->sign_mask ();
+      for (i = op0->len; i < op1->len; i++)
+	{
+	  o0 = op0->val[i];
+	  o1 = mask;
+	  x = o0 - o1 - borrow;
+	  result.elt_ref (i) = x;
+	  borrow = o0 < o1;
+	}
+    }
+  else if (op0->len > op1->len)
+    {
+      unsigned HOST_WIDE_INT mask = op0->sign_mask ();
+      for (i = op1->len; i < op0->len; i++)
+	{
+	  o0 = mask;
+	  o1 = op1->val[i];
+	  x = o0 - o1 - borrow;
+	  result.val[i] = x;
+	  borrow = o0 < o1;
+	}
+    }
+
+  if (op0->len * HOST_BITS_PER_WIDE_INT < op0->precision)
+    {
+      /* If the borrow is 1, then we need another word.  If the borrow
+	 is 0, we only need another word if the top bit is 1.  */
+      if (borrow == 1
+	  || (x >> (HOST_BITS_PER_WIDE_INT - 1) == 1))
+	{
+	  /* Check for signed overflow.  */
+	  result.val[result.len] = borrow;
+	  result.len++;
+	}
+    }
+
+  result.set_len (op0->len);
+  small_prec = op0->precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (sgn == wide_int::SIGNED)
+	{
+	  if (((x ^ o0) & (x ^ o1)) >> (HOST_BITS_PER_WIDE_INT - 1))
+	    *overflow = true;
+	}
+      else if (borrow)
+	{
+	  if ((~o0) < o1)
+	    *overflow = true;
+	}
+      else
+	{
+	  if ((~o0) <= o1)
+	    *overflow = true;
+	}
+    }
+  else
+    {
+      /* Overflow in this case is easy since we can see bits beyond
+	 the precision.  If the value computed is not the sign
+	 extended value, then we have overflow.  */
+      unsigned HOST_WIDE_INT y;
+
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  Then the rest of the code just works.  */
+	  o0 = zext_hwi (o0, small_prec);
+	  o1 = zext_hwi (o1, small_prec);
+	  x = o0 + o1 + borrow;
+	}
+      /* Short integers and modes with weird precisions.  */
+      y = sext_hwi (x, small_prec);
+      result.len =  op1->len;
+      if (BLOCKS_NEEDED (op1->precision) == result.len && x != y)
+	*overflow = true;
+      /* Then put the sign extended form back because that is the
+	 canonical form.  */
+      result.val[result.len - 1] = y;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvww ("wide_int:: %s %d = (%s -O %s)\n", 
+		result, *overflow, *op0, *op1);
+#endif
+  return result;
+}
+
+/* sub X from THIS.  If overflow occurs, set OVERFLOW.  */
+
+wide_int
+wide_int::sub (const wide_int &x, SignOp sgn, bool *overflow) const
+{
+  return sub_overflow (this, &x, sgn, overflow);
+}
+
+/*
+ * Division and Mod
+ */
+
+/* Compute B_QUOTIENT and B_REMAINDER from B_DIVIDEND/B_DIVISOR.  The
+   algorithm is a small modification of the algorithm in Hacker's
+   Delight by Warren, which itself is a small modification of Knuth's
+   algorithm.  M is the number of significant elements of U however
+   there needs to be at least one extra element of B_DIVIDEND
+   allocated, N is the number of elements of B_DIVISOR.  */
+
+static void
+divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+		   unsigned HOST_HALF_WIDE_INT *b_remainder,
+		   unsigned HOST_HALF_WIDE_INT *b_dividend, 
+		   unsigned HOST_HALF_WIDE_INT *b_divisor, 
+		   int m, int n)
+{
+  /* The "digits" are a HOST_HALF_WIDE_INT which the size of half of a
+     HOST_WIDE_INT and stored in the lower bits of each word.  This
+     algorithm should work properly on both 32 and 64 bit
+     machines.  */
+  unsigned HOST_WIDE_INT b
+    = (unsigned HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT;
+  unsigned HOST_WIDE_INT qhat;   /* Estimate of quotient digit.  */
+  unsigned HOST_WIDE_INT rhat;   /* A remainder.  */
+  unsigned HOST_WIDE_INT p;      /* Product of two digits.  */
+  HOST_WIDE_INT s, i, j, t, k;
+
+  /* Single digit divisor.  */
+  if (n == 1)
+    {
+      k = 0;
+      for (j = m - 1; j >= 0; j--)
+	{
+	  b_quotient[j] = (k * b + b_dividend[j])/b_divisor[0];
+	  k = ((k * b + b_dividend[j])
+	       - ((unsigned HOST_WIDE_INT)b_quotient[j]
+		  * (unsigned HOST_WIDE_INT)b_divisor[0]));
+	}
+      b_remainder[0] = k;
+      return;
+    }
+
+  s = clz_hwi (b_divisor[n-1]) - HOST_BITS_PER_HALF_WIDE_INT; /* CHECK clz */
+
+  /* Normalize B_DIVIDEND and B_DIVISOR.  Unlike the published
+     algorithm, we can overwrite b_dividend and b_divisor, so we do
+     that.  */
+  for (i = n - 1; i > 0; i--)
+    b_divisor[i] = (b_divisor[i] << s)
+      | (b_divisor[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_divisor[0] = b_divisor[0] << s;
+
+  b_dividend[m] = b_dividend[m-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s);
+  for (i = m - 1; i > 0; i--)
+    b_dividend[i] = (b_dividend[i] << s)
+      | (b_dividend[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_dividend[0] = b_dividend[0] << s;
+
+  /* Main loop.  */
+  for (j = m - n; j >= 0; j--)
+    {
+      qhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) / b_divisor[n-1];
+      rhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) - qhat * b_divisor[n-1];
+    again:
+      if (qhat >= b || qhat * b_divisor[n-2] > b * rhat + b_dividend[j+n-2])
+	{
+	  qhat -= 1;
+	  rhat += b_divisor[n-1];
+	  if (rhat < b)
+	    goto again;
+	}
+
+      /* Multiply and subtract.  */
+      k = 0;
+      for (i = 0; i < n; i++)
+	{
+	  p = qhat * b_divisor[i];
+	  t = b_dividend[i+j] - k - (p & HALF_INT_MASK);
+	  b_dividend[i + j] = t;
+	  k = ((p >> HOST_BITS_PER_HALF_WIDE_INT)
+	       - (t >> HOST_BITS_PER_HALF_WIDE_INT));
+	}
+      t = b_dividend[j+n] - k;
+      b_dividend[j+n] = t;
+
+      b_quotient[j] = qhat;
+      if (t < 0)
+	{
+	  b_quotient[j] -= 1;
+	  k = 0;
+	  for (i = 0; i < n; i++)
+	    {
+	      t = (HOST_WIDE_INT)b_dividend[i+j] + b_divisor[i] + k;
+	      b_dividend[i+j] = t;
+	      k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	    }
+	  b_dividend[j+n] += k;
+	}
+    }
+  for (i = 0; i < n; i++)
+    b_remainder[i] = (b_dividend[i] >> s) 
+      | (b_dividend[i+1] << (HOST_BITS_PER_HALF_WIDE_INT - s));
+}
+
+
+/* Do a truncating divide DIVISOR into DIVIDEND.  The result is the
+   same size as the operands.  SIGN is either wide_int::SIGNED or
+   wide_int::UNSIGNED.  */
+
+static wide_int
+divmod_internal (bool compute_quotient, 
+		 const wide_int *dividend, const wide_int *divisor,
+		 wide_int::SignOp sgn, wide_int *remainder,
+		 bool compute_remainder, 
+		 bool *overflow)
+{
+  wide_int quotient, u0, u1;
+  unsigned int prec = dividend->get_precision();
+  unsigned int bs = dividend->get_bitsize ();
+  int blocks_needed = 2 * BLOCKS_NEEDED (prec);
+  /* The '2' in the next 4 vars are because they are built on half
+     sized wide ints.  */
+  unsigned HOST_HALF_WIDE_INT 
+    b_quotient[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_remainder[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_dividend[(MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT) + 1];
+  unsigned HOST_HALF_WIDE_INT
+    b_divisor[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  int m, n;
+  bool dividend_neg = false;
+  bool divisor_neg = false;
+
+  if ((*divisor).zero_p ())
+    *overflow = true;
+
+  /* The smallest signed number / -1 causes overflow.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      wide_int t = wide_int::set_bit_in_zero (prec - 1, 
+					      bs, 
+					      prec);
+      if (*dividend == t && (*divisor).minus_one_p ())
+	*overflow = true;
+    }
+
+  quotient.set_bitsize (bs);
+  remainder->set_bitsize (bs);
+  quotient.set_precision (prec);
+  remainder->set_precision (prec);
+
+  /* If overflow is set, just get out.  There will only be grief by
+     continuing.  */
+  if (*overflow)
+    {
+      if (compute_remainder)
+	{
+	  remainder->set_len (1);
+	  remainder->elt_ref (0) = 0;
+	}
+      return wide_int::zero (bs, prec);
+    }
+
+  /* Do it on the host if you can.  */
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      quotient.set_len (1);
+      remainder->set_len (1);
+      if (sgn == wide_int::SIGNED)
+	{
+	  quotient.elt_ref (0) 
+	    = sext_hwi (dividend->elt (0) / divisor->elt (0), prec);
+	  remainder->elt_ref (0) 
+	    = sext_hwi (dividend->elt (0) % divisor->elt (0), prec);
+	}
+      else
+	{
+	  unsigned HOST_WIDE_INT o0 = dividend->elt (0);
+	  unsigned HOST_WIDE_INT o1 = divisor->elt (0);
+
+	  if (prec < HOST_BITS_PER_WIDE_INT)
+	    {
+	      o0 = zext_hwi (o0, prec);
+	      o1 = zext_hwi (o1, prec);
+	    }
+	  quotient.elt_ref (0) = sext_hwi (o0 / o1, prec);
+	  remainder->elt_ref (0) = sext_hwi (o0 % o1, prec);
+	}
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwww ("wide_int:: (q = %s) (r = %s) = (%s / %s)\n", 
+		    quotient, *remainder, *dividend, *divisor);
+#endif
+      return quotient;
+    }
+
+  /* Make the divisor and divident positive and remember what we
+     did.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      if (dividend->sign_mask ())
+	{
+	  u0 = dividend->neg ();
+	  dividend = &u0;
+	  dividend_neg = true;
+	}
+      if (divisor->sign_mask ())
+	{
+	  u1 = divisor->neg ();
+	  divisor = &u1;
+	  divisor_neg = true;
+	}
+    }
+
+  wi_unpack (b_dividend, &dividend->uelt_ref (0), dividend->get_len (),
+	     blocks_needed);
+  wi_unpack (b_divisor, &divisor->uelt_ref (0), divisor->get_len (),
+	     blocks_needed);
+
+  if (dividend->sign_mask ())
+    m = blocks_needed;
+  else
+    m = 2 * dividend->get_len ();
+
+  if (divisor->sign_mask ())
+    n = blocks_needed;
+  else
+    n = 2 * divisor->get_len ();
+
+  /* It is known that the top input block to the divisor is non zero,
+     but when this block is split into two half blocks, it may be that
+     the top half block is zero.  Skip over this half block.  */
+  if (b_divisor[n - 1] == 0)
+    n--;
+
+  divmod_internal_2 (b_quotient, b_remainder, b_dividend, b_divisor, m, n);
+
+  if (compute_quotient)
+    {
+      wi_pack (&quotient.uelt_ref (0), b_quotient, m);
+      quotient.set_len (m / 2);
+      quotient.canonize ();
+      /* The quotient is neg if exactly one of the divisor or dividend is
+	 neg.  */
+      if (dividend_neg != divisor_neg)
+	quotient = quotient.neg ();
+    }
+  else
+    quotient = wide_int::zero (word_mode);
+
+  if (compute_remainder)
+    {
+      wi_pack (&remainder->uelt_ref (0), b_remainder, n);
+      remainder->set_len (n / 2);
+      (*remainder).canonize ();
+      /* The remainder is always the same sign as the dividend.  */
+      if (dividend_neg)
+	*remainder = (*remainder).neg ();
+    }
+  else
+    *remainder = wide_int::zero (word_mode);
+
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwww ("wide_int:: (q = %s) (r = %s) = (%s / %s)\n", 
+		quotient, *remainder, *dividend, *divisor);
+#endif
+  return quotient;
+}
+
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is
+   truncated.  */
+
+wide_int
+wide_int::div_trunc (const wide_int &divisor, SignOp sgn) const
+{
+  wide_int remainder;
+  bool overflow = false;
+
+  return divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, false, &overflow);
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is truncated.
+   Overflow is set to true if the result overflows, otherwise it is
+   not set.  */
+wide_int
+wide_int::div_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  
+  return divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, false, overflow);
+}
+
+/* Divide DIVISOR into THIS producing both the quotient and remainder.
+   The result is the same size as the operands.  The sign is specified
+   in SGN.  The output is truncated.  */
+
+wide_int
+wide_int::divmod_trunc (const wide_int &divisor, wide_int *remainder, SignOp sgn) const
+{
+  bool overflow = false;
+
+  return divmod_internal (true, this, &divisor, sgn, 
+			  remainder, true, &overflow);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  */
+
+wide_int
+wide_int::mod_trunc (const wide_int &divisor, SignOp sgn) const
+{
+  bool overflow = false;
+  wide_int remainder;
+
+  divmod_internal (false, this, &divisor, sgn, 
+		   &remainder, true, &overflow);
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+
+  divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, true, overflow);
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is floor
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return quotient - wide_int::one (bitsize, precision);
+  return quotient;
+}
+
+
+/* Divide DIVISOR into THIS.  The remainder is also produced in
+   REMAINDER.  The result is the same size as the operands.  The sign
+   is specified in SGN.  The output is floor truncated.  Overflow is
+   set to true if the result overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::divmod_floor (const wide_int &divisor, wide_int *remainder, SignOp sgn) const
+{
+  wide_int quotient;
+  bool overflow = false;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      remainder, true, &overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !(*remainder).zero_p ())
+    {
+      *remainder = *remainder - divisor;
+      return quotient - wide_int::one (bitsize, precision);
+    }
+  return quotient;
+}
+
+
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is floor truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return remainder - divisor;
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is ceil
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return quotient;
+      else
+	return quotient + wide_int::one (bitsize, precision);
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is the
+   same size as the operands.  The sign is specified in SGN.  The
+   output is ceil truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return remainder;
+      else
+	return remainder - divisor;
+    }
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is round
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_round (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+  if (!remainder.zero_p ())
+    {
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return quotient - wide_int::one (bitsize, precision);
+	      else 
+		return quotient + wide_int::one (bitsize, precision);
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return quotient + wide_int::one (bitsize, precision);
+	}
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is round truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_round (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return remainder + divisor;
+	      else 
+		return remainder - divisor;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return remainder - divisor;
+	}
+    }
+  return remainder;
+}
+
+/*
+ * Shifting, rotating and extraction.
+ */
+
+/* If SHIFT_COUNT_TRUNCATED is defined, truncate CNT.   
+
+   At first look, the shift truncation code does not look right.
+   Shifts (and rotates) are done according to the precision of the
+   mode but the shift count is truncated according to the bitsize
+   of the mode.   This is how real hardware works.
+
+   On an ideal machine, like Knuth's mix machine, a shift count is a
+   word long and all of the bits of that word are examined to compute
+   the shift amount.  But on real hardware, especially on machines
+   with fast (single cycle shifts) that takes too long.  On these
+   machines, the amount of time to perform a shift dictates the cycle
+   time of the machine so corners are cut to keep this fast.  A
+   comparison of an entire 64 bit word would take something like 6
+   gate delays before the shifting can even start.
+
+   So real hardware only looks at a small part of the shift amount.
+   On ibm machines, this tends to be 1 more than what is necessary to
+   encode the shift amount.  The rest of the world looks at only the
+   minimum number of bits.  This means that only 3 gate delays are
+   necessary to set up the shifter.
+
+   On the other hand, right shifts and rotates must be according to
+   the precision or the operation does not make any sense.   */
+static inline int
+trunc_shift (unsigned int bitsize, int cnt)
+{
+#ifdef SHIFT_COUNT_TRUNCATED
+  cnt = cnt & (bitsize - 1);
+#endif
+  return cnt;
+}
+
+/* This function is called in two contexts.  If OP == TRUNC, this
+   function provides a count that matches the semantics of the target
+   machine depending on the value of SHIFT_COUNT_TRUNCATED.  Note that
+   if SHIFT_COUNT_TRUNCATED is not defined, this function may produce
+   -1 as a value if the shift amount is greater than the bitsize of
+   the mode.  -1 is a surrogate for a very large amount.
+
+   If OP == NONE, then this function always truncates the shift value
+   to the bitsize because this shifting operation is a function that
+   is internal to GCC.  */
+
+static inline int
+trunc_shift (unsigned int bitsize, const wide_int *cnt, wide_int::ShiftOp z)
+{
+  if (z == wide_int::TRUNC)
+    {
+#ifdef SHIFT_COUNT_TRUNCATED
+      return cnt->elt (0) & (bitsize - 1);
+#else
+      if (cnt.ltu (bitsize))
+	return cnt->elt (0) & (bitsize - 1);
+      else 
+	return -1;
+#endif
+    }
+  else
+    return cnt->elt (0) & (bitsize - 1);
+}
+
+/* Extract WIDTH bits from THIS starting at OFFSET.  The result is
+   assumed to fit in a HOST_WIDE_INT.  This function is safe in that
+   it can properly access elements that may not be explicitly
+   represented.  */
+
+HOST_WIDE_INT
+wide_int::extract_to_hwi (int offset, int width) const
+{
+  int start_elt, end_elt, shift;
+  HOST_WIDE_INT x;
+
+  /* Get rid of the easy cases first.   */
+  if (offset >= len * HOST_BITS_PER_WIDE_INT)
+    return sign_mask ();
+  if (offset + width <= 0)
+    return 0;
+
+  shift = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset < 0)
+    {
+      start_elt = -1;
+      end_elt = 0;
+      x = 0;
+    }
+  else
+    {
+      start_elt = offset / HOST_BITS_PER_WIDE_INT;
+      end_elt = (offset + width - 1) / HOST_BITS_PER_WIDE_INT;
+      x = start_elt >= len ? sign_mask () : val[start_elt] >> shift;
+    }
+
+  if (start_elt != end_elt)
+    {
+      HOST_WIDE_INT y = end_elt == len
+	? sign_mask () : val[end_elt];
+
+      x = (unsigned HOST_WIDE_INT)x >> shift;
+      x |= y << (HOST_BITS_PER_WIDE_INT - shift);
+    }
+
+  if (width != HOST_BITS_PER_WIDE_INT)
+    x &= ((HOST_WIDE_INT)1 << width) - 1;
+
+  return x;
+}
+
+
+/* Left shift by an integer Y.  See the definition of Op.TRUNC for how
+   to set Z.  */
+
+wide_int
+wide_int::lshift (unsigned int y, ShiftOp z) const
+{
+  return lshift (y, z, bitsize, precision);
+}
+
+/* Left shifting by an wide_int shift amount.  See the definition of
+   Op.TRUNC for how to set Z.  */
+
+wide_int
+wide_int::lshift (const wide_int &y, ShiftOp z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (bitsize, &y, TRUNC);
+      if (shift == -1)
+	return wide_int::zero (bitsize, precision);
+      return lshift (shift, NONE, bitsize, precision);
+    }
+  else
+    return lshift (trunc_shift (bitsize, &y, NONE), NONE, bitsize, precision);
+}
+
+/* Left shift THIS by CNT.  See the definition of Op.TRUNC for how to
+   set Z.  Since this is used internally, it has the ability to
+   specify the BISIZE and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+wide_int
+wide_int::lshift (unsigned int cnt, ShiftOp op, 
+		  unsigned int bs, unsigned int res_prec) const
+{
+  wide_int result;
+  unsigned int i;
+
+  result.bitsize = bs;
+  result.precision = res_prec;
+
+  if (op == TRUNC)
+    cnt = trunc_shift (bs, cnt);
+
+  /* Handle the simple case quickly.   */
+  if (res_prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[0] = val[0] << cnt;
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s << %d)\n", result, *this, cnt);
+#endif
+
+      return result;
+    }
+
+  if (cnt >= res_prec)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int:: %s = (%s << %d)\n", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  for (i = 0; i < res_prec; i += HOST_BITS_PER_WIDE_INT)
+    result.val[i / HOST_BITS_PER_WIDE_INT]
+      = extract_to_hwi (i - cnt, HOST_BITS_PER_WIDE_INT);
+
+  result.len = BLOCKS_NEEDED (res_prec);
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s << %d)\n", result, *this, cnt);
+#endif
+
+  return result;
+}
+
+/* Rotate THIS left by Y within its precision.  */
+
+wide_int
+wide_int::lrotate (const wide_int &y) const
+{
+  return lrotate (y.extract_to_hwi (0, HOST_BITS_PER_WIDE_INT));
+}
+
+/* Rotate THIS left by CNT within its precision.  */
+
+wide_int
+wide_int::lrotate (unsigned int cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (cnt, NONE);
+  right = rshiftu (precision - cnt, NONE);
+  result = left | right;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s lrotate %d)\n", result, *this, cnt);
+#endif
+  return result;
+}
+
+/* Unsigned right shift by Y.  See the definition of Op.TRUNC for how
+   to set Z.  */
+
+wide_int
+wide_int::rshiftu (const wide_int &y, ShiftOp z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (bitsize, &y, TRUNC);
+      if (shift == -1)
+	return wide_int::zero (bitsize, precision);
+      return rshiftu (shift, NONE);
+    }
+  else
+    return rshiftu (trunc_shift (bitsize, &y, NONE), NONE);
+}
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set Z.  */
+
+wide_int
+wide_int::rshiftu (unsigned int cnt, ShiftOp trunc_op) const
+{
+  wide_int result;
+  int stop_block, offset, i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (trunc_op == TRUNC)
+    cnt = trunc_shift (bitsize, cnt);
+
+  if (cnt == 0)
+    {
+      result = force_to_size (bitsize, precision, UNSIGNED);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int:: %s = (%s >>U %d)\n", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  /* Handle the simple case quickly.   */
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT x = val[0];
+
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	x = zext_hwi (x, precision);
+
+      result.val[0] = x >> cnt;
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s >>U %d)\n", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  if (cnt >= precision)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s >>U %d)\n", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  offset = (precision - cnt) & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset)
+    result.val[stop_block - 1] = zext_hwi (result.val[stop_block - 1], offset);
+  else
+    /* The top block had a 1 at the top position so it will decompress
+       wrong unless a zero block is added.  This only works because we
+       know the shift was greater than 0.  */
+    if (result.val[stop_block - 1] < 0)
+      result.val[result.len++] = 0;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s >>U %d)\n", result, *this, cnt);
+#endif
+  return result;
+}
+
+/* Signed right shift by Y.  See the definition of Op.TRUNC for how to
+   set Z.  */
+wide_int
+wide_int::rshifts (const wide_int &y, ShiftOp z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (bitsize, &y, TRUNC);
+      if (shift == -1)
+	{
+	  /* The value of the shift was larger than the bitsize and this
+	     machine does not truncate the value, so the result is
+	     a smeared sign bit.  */
+	  if (neg_p ())
+	    return wide_int::minus_one (bitsize, precision);
+	  else
+	    return wide_int::zero (bitsize, precision);
+	}
+      return rshifts (shift, NONE);
+    }
+  else
+    return rshifts (trunc_shift (bitsize, &y, NONE), NONE);
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set Z.  */
+
+wide_int
+wide_int::rshifts (unsigned int cnt, ShiftOp trunc_op) const
+{
+  wide_int result;
+  int stop_block, i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (trunc_op == TRUNC)
+    cnt = trunc_shift (bitsize, cnt);
+
+  if (cnt == 0)
+    {
+      result = force_to_size (bitsize, precision, SIGNED);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int:: %s = (%s >>S %d)\n", result, *this, cnt);
+#endif
+      return result;
+    }
+  /* Handle the simple case quickly.   */
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT x = val[0];
+      result.val[0] = x >> cnt;
+      result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int:: %s = (%s >>S %d)\n", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  if (cnt >= precision)
+    {
+      HOST_WIDE_INT m = sign_mask ();
+      result.val[0] = m;
+      result.len = 1;
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwv ("wide_int:: %s = (%s >>S %d)\n", result, *this, cnt);
+#endif
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  /* No need to sign extend the last block, since it extract_to_hwi
+     already did that.  */
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s >>S %d)\n", result, *this, cnt);
+#endif
+
+  return result;
+}
+
+/* Rotate THIS right by Y within its precision.  */
+
+wide_int
+wide_int::rrotate (const wide_int &y) const
+{
+  return rrotate (y.extract_to_hwi (0, HOST_BITS_PER_WIDE_INT));
+}
+
+/* Rotate THIS right by CNT within its precision.  */
+
+wide_int
+wide_int::rrotate (int cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (precision - cnt, NONE);
+  right = rshiftu (cnt, NONE);
+  result = left | right;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s rrotate %d)\n", result, *this, cnt);
+#endif
+  return result;
+}
+
+/*
+ * Private utilities.
+ */
+/* Decompress THIS for at least TARGET bits into a result with bitsize
+   BS and precision PREC.  */
+
+wide_int
+wide_int::decompress (unsigned int target, 
+		      unsigned int bs, unsigned int prec) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (target);
+  HOST_WIDE_INT mask;
+  int len, i;
+
+  result.bitsize = bs;
+  result.precision = prec;
+  result.len = blocks_needed;
+
+  for (i = 0; i < this->len; i++)
+    result.val[i] = val[i];
+
+  len = this->len;
+
+  if (target > result.precision)
+    return result;
+
+  /* The extension that we are doing here is not sign extension, it is
+     decompression.  */
+  mask = sign_mask ();
+  while (len < blocks_needed)
+    result.val[len++] = mask;
+
+  return result;
+}
+
+
+/*
+ * Private debug printing routines.
+ */
+
+/* The debugging routines print results of wide operations into the
+   dump files of the respective passes in which they were called.  */
+char *
+wide_int::dump (char* buf) const
+{
+  int i;
+  int l;
+  const char * sep = "";
+
+  l = sprintf (buf, "[%d,%d (", bitsize, precision);
+  for (i = len - 1; i >= 0; i--)
+    {
+      l += sprintf (&buf[l], "%s" HOST_WIDE_INT_PRINT_HEX, sep, val[i]);
+      sep = " ";
+    }
+
+  gcc_assert (len != 0);
+
+  l += sprintf (&buf[l], ")]");
+
+  gcc_assert (l < MAX);
+  return buf;
+}
+
+#ifdef DEBUG_WIDE_INT
+void
+debug_vw (const char* fmt, int r, const wide_int& o0)
+{
+  char buf0[MAX];
+  fprintf (dump_file, fmt, r, o0.dump (buf0));
+}
+
+void
+debug_vwh (const char* fmt, int r, const wide_int &o0,
+	   HOST_WIDE_INT o1)
+{
+  char buf0[MAX];
+  fprintf (dump_file, fmt, r, o0.dump (buf0), o1);
+}
+
+void
+debug_vww (const char* fmt, int r, const wide_int &o0,
+	   const wide_int &o1)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  fprintf (dump_file, fmt, r, o0.dump (buf0), o1.dump (buf1));
+}
+
+void
+debug_whh (const char* fmt, const wide_int &r,
+	   HOST_WIDE_INT o1, HOST_WIDE_INT o2)
+{
+  char buf0[MAX];
+  fprintf (dump_file, fmt, r.dump (buf0), o1, o2);
+}
+
+void
+debug_wv (const char* fmt, const wide_int &r, int v0)
+{
+  char buf0[MAX];
+  fprintf (dump_file, fmt, r.dump (buf0), v0);
+}
+
+void
+debug_wvv (const char* fmt, const wide_int &r, int v0, int v1)
+{
+  char buf0[MAX];
+  fprintf (dump_file, fmt, r.dump (buf0), v0, v1);
+}
+
+void
+debug_wvvv (const char* fmt, const wide_int &r, int v0, int v1, int v2)
+{
+  char buf0[MAX];
+  fprintf (dump_file, fmt, r.dump (buf0), v0, v1, v2);
+}
+
+void
+debug_wvww (const char* fmt, const wide_int &r, int v0,
+	    const wide_int &o0, const wide_int &o1)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  char buf2[MAX];
+  fprintf (dump_file, fmt, r.dump (buf0), v0, o0.dump (buf1), o1.dump (buf2));
+}
+
+void
+debug_ww (const char* fmt, const wide_int &r, const wide_int &o0)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1));
+}
+
+void
+debug_wwv (const char* fmt, const wide_int &r,
+	   const wide_int &o0, int v0)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1), v0);
+}
+
+void
+debug_wwvvs (const char* fmt, const wide_int &r, 
+	     const wide_int &o0, int v0, int v1, const char *s)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1), v0, v1, s);
+}
+
+void
+debug_wwwvv (const char* fmt, const wide_int &r,
+	     const wide_int &o0, const wide_int &o1, int v0, int v1)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  char buf2[MAX];
+  fprintf (dump_file, fmt, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), v0, v1);
+}
+
+void
+debug_www (const char* fmt, const wide_int &r,
+	   const wide_int &o0, const wide_int &o1)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  char buf2[MAX];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1), o1.dump (buf2));
+}
+
+void
+debug_wwww (const char* fmt, const wide_int &r,
+	    const wide_int &o0, const wide_int &o1, const wide_int &o2)
+{
+  char buf0[MAX];
+  char buf1[MAX];
+  char buf2[MAX];
+  char buf3[MAX];
+  fprintf (dump_file, fmt, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), o2.dump (buf3));
+}
+#endif
+
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
new file mode 100644
index 0000000..f7815b9
--- /dev/null
+++ b/gcc/wide-int.h
@@ -0,0 +1,1355 @@
+/* Operations with very long integers.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef WIDE_INT_H
+#define WIDE_INT_H
+
+/* A wide integer is currently represented as a vector of
+   HOST_WIDE_INTs.  The vector contains enough elements to hold a
+   value of MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT which is
+   a derived for each host target combination.  The values are stored
+   in the vector with the least signicant HOST_BITS_PER_WIDE_INT bits
+   of the value stored in element 0.
+
+   A wide_int contains four fields: the vector (VAL), the bitsize,
+   precision and a length, (LEN).  The length is the number of HWIs
+   needed to represent the value.
+
+   Since most integers used in a compiler are small values, it is
+   generally profitable to use a representation of the value that is
+   shorter than the modes precision.  LEN is used to indicate the
+   number of elements of the vector that are in use.  When LEN *
+   HOST_BITS_PER_WIDE_INT < the precision, the value has been
+   compressed.  The values of the elements of the vector greater than
+   LEN - 1. are all equal to the highest order bit of LEN.
+
+   The representation does not contain any information about
+   signedness of the represented value, so it can be used to represent
+   both signed and unsigned numbers.  For operations where the results
+   depend on signedness (division, comparisons), the signedness must
+   be specified separately.  For operations where the signness
+   matters, one of the operands to the operation specifies either
+   wide_int::SIGNED or wide_int::UNSIGNED.
+
+   All constructors for wide_int take either a bitsize and precision,
+   an enum machine_mode or tree_type.  */
+
+
+#ifndef GENERATOR_FILE
+#include "tree.h"
+#include "hwint.h"
+#include "options.h"
+#include "tm.h"
+#include "insn-modes.h"
+#include "machmode.h"
+#include "double-int.h"
+#include <gmp.h>
+#include "insn-modes.h"
+
+
+class wide_int {
+  /* Internal representation.  */
+  
+  /* VAL is set to a size that is capable of computing a full
+     multiplication on the largest mode that is represented on the
+     target.  The full multiplication is use by tree-vrp.  tree-vpn
+     currently does a 2x largest mode by 2x largest mode yielding a 4x
+     largest mode result.  If operations are added that require larger
+     buffers, then VAL needs to be changed.  */
+  HOST_WIDE_INT val[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  unsigned short len;
+  unsigned int bitsize;
+  unsigned int precision;
+
+ public:
+  enum ShiftOp {
+    NONE,
+    /* There are two uses for the wide-int shifting functions.  The
+       first use is as an emulation of the target hardware.  The
+       second use is as service routines for other optimizations.  The
+       first case needs to be identified by passing TRUNC as the value
+       of ShiftOp so that shift amount is properly handled according to the
+       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
+       amount is always truncated by the bytesize of the mode of
+       THIS.  */
+    TRUNC
+  };
+
+  enum SignOp {
+    /* Many of the math functions produce different results depending
+       on if they are SIGNED or UNSIGNED.  In general, there are two
+       different functions, whose names are prefixed with an 'S" and
+       or an 'U'.  However, for some math functions there is also a
+       routine that does not have the prefix and takes an SignOp
+       parameter of SIGNED or UNSIGNED.  */
+    SIGNED,
+    UNSIGNED
+  };
+
+  /* Conversions.  */
+
+  static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize, 
+			     unsigned int precision);
+  static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize, 
+			     unsigned int precision, bool *overflow);
+  static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, unsigned int bitsize, 
+			     unsigned int precision);
+  static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, unsigned int bitsize, 
+			     unsigned int precision, bool *overflow);
+
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type);
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type, 
+				   bool *overflow);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+				    bool *overflow);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+				    enum machine_mode mode);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+				    enum machine_mode mode, 
+				    bool *overflow);
+
+  static wide_int from_double_int (double_int, 
+				   unsigned int bitsize, 
+				   unsigned int precision);
+  inline static wide_int from_double_int (double_int, enum machine_mode);
+  static wide_int from_tree (const_tree);
+  static wide_int from_tree_as_infinite_precision (const_tree tcst, 
+						   unsigned int bitsize, 
+						   unsigned int precision);
+  static wide_int from_rtx (const_rtx, enum machine_mode);
+
+  HOST_WIDE_INT to_shwi () const;
+  HOST_WIDE_INT to_shwi (unsigned int prec) const;
+  unsigned HOST_WIDE_INT to_uhwi () const;
+  unsigned HOST_WIDE_INT to_uhwi (unsigned int prec) const;
+
+  /* Largest and smallest values that are represented in modes or precisions.  */
+
+  static wide_int max_value (unsigned int bitsize, unsigned int prec, SignOp sgn);
+  static wide_int max_value (const_tree type);
+  static wide_int max_value (enum machine_mode mode, SignOp sgn);
+  
+  static wide_int min_value (unsigned int bitsize, unsigned int prec, SignOp sgn);
+  static wide_int min_value (const_tree type);
+  static wide_int min_value (enum machine_mode mode, SignOp sgn);
+  
+  /* Small constants */
+
+  inline static wide_int minus_one (unsigned int bitsize, unsigned int prec);
+  inline static wide_int minus_one (const_tree type);
+  inline static wide_int minus_one (enum machine_mode mode);
+  inline static wide_int minus_one (const wide_int &op1);
+  inline static wide_int zero (unsigned int bitsize, unsigned int prec);
+  inline static wide_int zero (const_tree type);
+  inline static wide_int zero (enum machine_mode mode);
+  inline static wide_int zero (const wide_int &op1);
+  inline static wide_int one (unsigned int bitsize, unsigned int prec);
+  inline static wide_int one (const_tree type);
+  inline static wide_int one (enum machine_mode mode);
+  inline static wide_int one (const wide_int &op1);
+  inline static wide_int two (unsigned int bitsize, unsigned int prec);
+  inline static wide_int two (const_tree type);
+  inline static wide_int two (enum machine_mode mode);
+  inline static wide_int two (const wide_int &op1);
+  inline static wide_int ten (unsigned int bitsize, unsigned int prec);
+  inline static wide_int ten (const_tree type);
+  inline static wide_int ten (enum machine_mode mode);
+  inline static wide_int ten (const wide_int &op1);
+
+  /* Accessors.  */
+
+  inline unsigned short get_len () const;
+  inline unsigned int get_bitsize () const;
+  inline unsigned int get_precision () const;
+  inline unsigned int get_full_len () const;
+  inline HOST_WIDE_INT elt (unsigned int i) const;
+
+  /* The setters should rarely be used.   They are for the few places
+     where wide_ints are constructed inside some other class.  */
+  inline void set_len (unsigned int);
+  inline void set_bitsize (unsigned int);
+  inline void set_precision (unsigned int);
+  inline HOST_WIDE_INT& elt_ref (unsigned int i);
+  inline unsigned HOST_WIDE_INT& uelt_ref (unsigned int i);
+  inline const unsigned HOST_WIDE_INT& uelt_ref (unsigned int i) const;
+
+  /* Utility routines.  */
+
+  void canonize ();
+
+  /* Printing functions.  */
+
+  void print_dec (char *buf, SignOp sgn) const;
+  void print_dec (FILE *file, SignOp sgn) const;
+  void print_decs (char *buf) const;
+  void print_decs (FILE *file) const;
+  void print_decu (char *buf) const;
+  void print_decu (FILE *file) const;
+  void print_hex (char *buf) const;
+  void print_hex (FILE *file) const;
+
+  /* Comparative functions.  */
+
+  inline bool minus_one_p () const;
+  inline bool zero_p () const;
+  inline bool one_p () const;
+  inline bool neg_p () const;
+
+  bool operator == (const wide_int &y) const;
+  inline bool operator != (const wide_int &y) const;
+  inline bool gt_p (HOST_WIDE_INT x, SignOp sgn) const;
+  inline bool gt_p (const wide_int &x, SignOp sgn) const;
+  bool gts_p (HOST_WIDE_INT y) const;
+  inline bool gts_p (const wide_int &y) const;
+  bool gtu_p (unsigned HOST_WIDE_INT y) const;
+  inline bool gtu_p (const wide_int &y) const;
+
+  inline bool lt_p (const HOST_WIDE_INT x, SignOp sgn) const;
+  inline bool lt_p (const wide_int &x, SignOp sgn) const;
+  bool lts_p (HOST_WIDE_INT y) const;
+  bool lts_p (const wide_int &y) const;
+  bool ltu_p (unsigned HOST_WIDE_INT y) const;
+  bool ltu_p (const wide_int &y) const;
+  inline int cmp (const wide_int &y, SignOp sgn) const;
+  int cmps (const wide_int &y) const;
+  int cmpu (const wide_int &y) const;
+
+  bool only_sign_bit_p (unsigned int prec) const;
+  bool only_sign_bit_p () const;
+  inline bool fits_uhwi_p () const;
+  inline bool fits_shwi_p () const;
+  bool fits_to_tree_p (const_tree type) const;
+  bool fits_u_p (unsigned int prec) const;
+  bool fits_s_p (unsigned int prec) const;
+
+  /* Min and max */
+
+  inline wide_int min (const wide_int &op1, SignOp sgn) const;
+  inline wide_int max (const wide_int &op1, SignOp sgn) const;
+  inline wide_int smin (const wide_int &op1) const;
+  inline wide_int smax (const wide_int &op1) const;
+  inline wide_int umin (const wide_int &op1) const;
+  inline wide_int umax (const wide_int &op1) const;
+
+  /* Extension, these do not change the precision or bitsize.  */
+
+  inline wide_int ext (unsigned int offset, SignOp sgn) const;
+  inline wide_int ext (enum machine_mode mode, SignOp sgn) const;
+  inline wide_int ext (const_tree type) const;
+  wide_int sext (unsigned int offset) const;
+  inline wide_int sext (enum machine_mode mode) const;
+  wide_int zext (unsigned int offset) const;
+  inline wide_int zext (enum machine_mode mode) const;
+
+  /* These change the underlying bitsize and precision.  */
+  
+  wide_int force_to_size (unsigned int bitsize, unsigned int precision, 
+			  SignOp sgn) const;
+  inline wide_int force_to_size (enum machine_mode mode, SignOp sgn) const;
+  inline wide_int force_to_size (const_tree type) const;
+  inline wide_int force_to_size (const_tree type, SignOp sgn) const;
+
+  inline wide_int sforce_to_size (enum machine_mode mode) const;
+  inline wide_int sforce_to_size (const_tree type) const;
+  inline wide_int zforce_to_size (enum machine_mode mode) const;
+  inline wide_int zforce_to_size (const_tree type) const;
+
+  /* Masking, and Insertion  */
+
+  wide_int set_bit (unsigned int bitpos) const;
+  static wide_int set_bit_in_zero (unsigned int, 
+				   unsigned int bitsize, 
+				   unsigned int prec);
+  inline static wide_int set_bit_in_zero (unsigned int, 
+					  enum machine_mode mode);
+  inline static wide_int set_bit_in_zero (unsigned int, const_tree type);
+  wide_int insert (const wide_int &op0, unsigned int offset,
+		   unsigned int width) const;
+  static wide_int mask (unsigned int start, bool negate, 
+			unsigned int bitsize, unsigned int prec);
+  inline static wide_int mask (unsigned int start, bool negate, 
+			       enum machine_mode mode);
+  inline static wide_int mask (unsigned int start, bool negate,
+			       const_tree type);
+  wide_int bswap () const;
+  static wide_int shifted_mask (unsigned int start, unsigned int width,
+				bool negate,
+				unsigned int bitsize, unsigned int prec);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, enum machine_mode mode);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, const_tree type);
+  inline HOST_WIDE_INT sign_mask () const;
+
+  /* Logicals */
+
+  wide_int operator & (const wide_int &y) const;
+  wide_int and_not (const wide_int &y) const;
+  wide_int operator ~ () const;
+  wide_int or_not (const wide_int &y) const;
+  wide_int operator | (const wide_int &y) const;
+  wide_int operator ^ (const wide_int &y) const;
+
+  /* Arithmetic operation functions, alpha sorted.  */
+  wide_int abs () const;
+  wide_int operator + (const wide_int &y) const;
+  wide_int add (const wide_int &x, SignOp sgn, bool *overflow) const;
+  wide_int clz (unsigned int bitsize, unsigned int prec) const;
+  int clz () const;
+  wide_int clrsb (unsigned int bitsize, unsigned int prec) const;
+  int clrsb () const;
+  wide_int ctz (unsigned int bitsize, unsigned int prec) const;
+  int ctz () const;
+  int exact_log2 () const;
+  int floor_log2 () const;
+  wide_int ffs () const;
+  wide_int operator * (const wide_int &y) const;
+  wide_int mul (const wide_int &x, SignOp sgn, bool *overflow) const;
+  inline wide_int smul (const wide_int &x, bool *overflow) const;
+  inline wide_int umul (const wide_int &x, bool *overflow) const;
+  wide_int mul_full (const wide_int &x, SignOp sgn) const;
+  inline wide_int umul_full (const wide_int &x) const;
+  inline wide_int smul_full (const wide_int &x) const;
+  wide_int mul_high (const wide_int &x, SignOp sgn) const;
+  wide_int neg () const;
+  wide_int neg_overflow (bool *z) const;
+  wide_int parity (unsigned int bitsize, unsigned int prec) const;
+  int popcount () const;
+  wide_int popcount (unsigned int bitsize, unsigned int prec) const;
+  wide_int operator - (const wide_int &y) const;
+  wide_int sub (const wide_int &x, SignOp sgn, bool *overflow) const;
+
+  /* Divison and mod.  These are the ones that are actually used, but
+     there are a lot of them.  */
+
+  wide_int div_trunc (const wide_int &divisor, SignOp sgn) const;
+  wide_int div_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int sdiv_trunc (const wide_int &divisor) const;
+  inline wide_int udiv_trunc (const wide_int &divisor) const;
+
+  wide_int div_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int udiv_floor (const wide_int &divisor) const;
+  inline wide_int sdiv_floor (const wide_int &divisor) const;
+  wide_int div_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  wide_int div_round (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+
+  wide_int divmod_trunc (const wide_int &divisor, wide_int *mod, SignOp sgn) const;
+  inline wide_int sdivmod_trunc (const wide_int &divisor, wide_int *mod) const;
+  inline wide_int udivmod_trunc (const wide_int &divisor, wide_int *mod) const;
+
+  wide_int divmod_floor (const wide_int &divisor, wide_int *mod, SignOp sgn) const;
+  inline wide_int sdivmod_floor (const wide_int &divisor, wide_int *mod) const;
+
+  wide_int mod_trunc (const wide_int &divisor, SignOp sgn) const;
+  wide_int mod_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int smod_trunc (const wide_int &divisor) const;
+  inline wide_int umod_trunc (const wide_int &divisor) const;
+
+  wide_int mod_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int umod_floor (const wide_int &divisor) const;
+  wide_int mod_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  wide_int mod_round (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+
+  /* Shifting rotating and extracting.  */
+  HOST_WIDE_INT extract_to_hwi (int offset, int width) const;
+
+  wide_int lshift (const wide_int &y, ShiftOp z = NONE) const;
+  wide_int lshift (unsigned int y, ShiftOp z, unsigned int bitsize, 
+		   unsigned int precision) const;
+  wide_int lshift (unsigned int y, ShiftOp z = NONE) const;
+
+  wide_int lrotate (const wide_int &y) const;
+  wide_int lrotate (unsigned int y) const;
+
+  wide_int rshift (int y, SignOp sgn) const;
+  inline wide_int rshift (const wide_int &y, SignOp sgn, ShiftOp z = NONE) const;
+  wide_int rshiftu (const wide_int &y, ShiftOp z = NONE) const;
+  wide_int rshiftu (unsigned int y, ShiftOp z = NONE) const;
+  wide_int rshifts (const wide_int &y, ShiftOp z = NONE) const;
+  wide_int rshifts (unsigned int y, ShiftOp z = NONE) const;
+
+  wide_int rrotate (const wide_int &y) const;
+  wide_int rrotate (int y) const;
+
+  static const int DUMP_MAX = (2 * (MAX_BITSIZE_MODE_ANY_INT / 4
+			       + MAX_BITSIZE_MODE_ANY_INT 
+				    / HOST_BITS_PER_WIDE_INT + 32));
+  char *dump (char* buf) const;
+ private:
+
+  /* Private utility routines.  */
+  wide_int decompress (unsigned int target, unsigned int bitsize, 
+		       unsigned int precision) const;
+  static wide_int add_overflow (const wide_int *op0, const wide_int *op1,
+				wide_int::SignOp sgn, bool *overflow);
+  static wide_int sub_overflow (const wide_int *op0, const wide_int *op1, 
+				wide_int::SignOp sgn, bool *overflow);
+};
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with bitsize
+   and precision taken from MODE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, enum machine_mode mode)
+{
+  return wide_int::set_bit_in_zero (bitpos, GET_MODE_BITSIZE (mode),
+				    GET_MODE_PRECISION (mode));
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with bitsize
+   and precision taken from TYPE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, const_tree type)
+{
+
+  return wide_int::set_bit_in_zero (bitpos, 
+				    GET_MODE_BITSIZE (TYPE_MODE (type)),
+				    TYPE_PRECISION (type));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.   The result is made with bitsize
+   and precision taken from MODE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, enum machine_mode mode)
+{
+  return wide_int::mask (width, negate, 
+			 GET_MODE_BITSIZE (mode),
+			 GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with bitsize
+   and precision taken from TYPE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, const_tree type)
+{
+
+  return wide_int::mask (width, negate, 
+			 GET_MODE_BITSIZE (TYPE_MODE (type)),
+			 TYPE_PRECISION (type));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the bits
+   above that up to the precision are zeros.  The result is inverted
+   if NEGATE is true.  The result is made with bitsize and precision
+   taken from MODE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, enum machine_mode mode)
+{
+  return wide_int::shifted_mask (start, width, negate, 
+				 GET_MODE_BITSIZE (mode),
+				 GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with bitsize
+   and precision taken from TYPE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, const_tree type)
+{
+
+  return wide_int::shifted_mask (start, width, negate, 
+				 GET_MODE_BITSIZE (TYPE_MODE (type)),
+				 TYPE_PRECISION (type));
+}
+
+/* Produce 0 or -1 that is the smear of the sign bit.  */
+
+HOST_WIDE_INT
+wide_int::sign_mask () const
+{
+  int i = len - 1;
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
+	    >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* VRP appears to be badly broken and this is a very ugly fix.  */
+  if (i >= 0)
+    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
+
+  gcc_unreachable ();
+#if 0
+  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
+#endif
+}
+
+/* Conversions */
+
+/* Convert OP0 into a wide_int with parameters taken from TYPE.  */
+
+wide_int
+wide_int::from_hwi (HOST_WIDE_INT op0, const_tree type)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return wide_int::from_uhwi (op0, bitsize, prec);
+  else
+    return wide_int::from_shwi (op0, bitsize, prec);
+}
+
+/* Convert OP0 into a wide_int with parameters taken from TYPE.  If
+   the value does not fit, set OVERFLOW.  */
+
+wide_int
+wide_int::from_hwi (HOST_WIDE_INT op0, const_tree type, 
+		    bool *overflow)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return wide_int::from_uhwi (op0, bitsize, prec, overflow);
+  else
+    return wide_int::from_shwi (op0, bitsize, prec, overflow);
+}
+
+/* Convert signed OP0 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_shwi (op0, bitsize, prec);
+}
+
+/* Convert signed OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+	   bool *overflow)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_shwi (op0, bitsize, prec, overflow);
+}
+
+/* Convert unsigned OP0 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_uhwi (op0, bitsize, prec);
+}
+
+/* Convert unsigned OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode, 
+		     bool *overflow)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_uhwi (op0, bitsize, prec, overflow);
+}
+
+/* Convert double_int OP0 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_double_int (double_int op0, enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_double_int (op0, bitsize, prec);
+}
+
+/* Small constants.  */
+
+/* Return a wide int of -1 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::minus_one (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (-1, bs, prec);
+}
+
+/* Return a wide int of -1 with TYPE.  */
+
+wide_int
+wide_int::minus_one (const_tree type)
+{
+  return wide_int::from_shwi (-1, TYPE_MODE (type));
+}
+
+/* Return a wide int of -1 with MODE.  */
+
+wide_int
+wide_int::minus_one (enum machine_mode mode)
+{
+  return wide_int::from_shwi (-1, mode);
+}
+
+/* Return a wide int of -1 that is the same size as op1.  */
+
+wide_int
+wide_int::minus_one (const wide_int &op1)
+{
+  return wide_int::from_shwi (-1, op1.get_bitsize (), op1.get_precision ());
+}
+
+
+/* Return a wide int of 0 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::zero (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (0, bs, prec);
+}
+
+/* Return a wide int of 0 with TYPE.  */
+
+wide_int
+wide_int::zero (const_tree type)
+{
+  return wide_int::from_shwi (0, TYPE_MODE (type));
+}
+
+/* Return a wide int of 0 with MODE.  */
+
+wide_int
+wide_int::zero (enum machine_mode mode)
+{
+  return wide_int::from_shwi (0, mode);
+}
+
+/* Return a wide int of 0 that is the same size as op1.  */
+
+wide_int
+wide_int::zero (const wide_int &op1)
+{
+  return wide_int::from_shwi (0, op1.get_bitsize (), op1.get_precision ());
+}
+
+
+/* Return a wide int of 1 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::one (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (1, bs, prec);
+}
+
+/* Return a wide int of 1 with TYPE.  */
+
+wide_int
+wide_int::one (const_tree type)
+{
+  return wide_int::from_shwi (1, TYPE_MODE (type));
+}
+
+/* Return a wide int of 1 with MODE.  */
+
+wide_int
+wide_int::one (enum machine_mode mode)
+{
+  return wide_int::from_shwi (1, mode);
+}
+
+/* Return a wide int of 1 that is the same size as op1.  */
+
+wide_int
+wide_int::one (const wide_int &op1)
+{
+  return wide_int::from_shwi (1, op1.get_bitsize (), op1.get_precision ());
+}
+
+
+/* Return a wide int of 2 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::two (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (2, bs, prec);
+}
+
+/* Return a wide int of 2 with TYPE.  */
+
+wide_int
+wide_int::two (const_tree type)
+{
+  return wide_int::from_shwi (2, TYPE_MODE (type));
+}
+
+/* Return a wide int of 2 with MODE.  */
+
+wide_int
+wide_int::two (enum machine_mode mode)
+{
+  return wide_int::from_shwi (2, mode);
+}
+
+/* Return a wide int of 2 that is the same size as op1.  */
+
+wide_int
+wide_int::two (const wide_int &op1)
+{
+  return wide_int::from_shwi (2, op1.get_bitsize (), op1.get_precision ());
+}
+
+
+/* Return a wide int of 10 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::ten (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (10, bs, prec);
+}
+
+/* Return a wide int of 10 with TYPE.  */
+
+wide_int
+wide_int::ten (const_tree type)
+{
+  return wide_int::from_shwi (10, TYPE_MODE (type));
+}
+
+/* Return a wide int of 10 with MODE.  */
+
+wide_int
+wide_int::ten (enum machine_mode mode)
+{
+  return wide_int::from_shwi (10, mode);
+}
+
+/* Return a wide int of 10 that is the same size as op1.  */
+
+wide_int
+wide_int::ten (const wide_int &op1)
+{
+  return wide_int::from_shwi (10, op1.get_bitsize (), op1.get_precision ());
+}
+
+
+/* Public accessors for the interior of a wide int.  */
+
+/* Get the number of host wide ints actually represented within the
+   wide int.  */
+
+unsigned short
+wide_int::get_len () const
+{
+  return len;
+}
+
+/* Get bitsize of the value represented within the wide int.  */
+
+unsigned int
+wide_int::get_bitsize () const
+{
+  return bitsize;
+}
+
+/* Get precision of the value represented within the wide int.  */
+
+unsigned int
+wide_int::get_precision () const
+{
+  return precision;
+}
+
+/* Get the number of host wide ints needed to represent the precision
+   of the number.  NOTE that this should rarely be used.  The only
+   clients of this are places like dwarf2out where you need to
+   explicitly write all of the HWIs that are needed to represent the
+   value. */
+
+unsigned int
+wide_int::get_full_len () const
+{
+  return ((precision + HOST_BITS_PER_WIDE_INT - 1)
+	  / HOST_BITS_PER_WIDE_INT);
+}
+
+/* Get a particular element of the wide int.  */
+
+HOST_WIDE_INT
+wide_int::elt (unsigned int i) const
+{
+  return i >= len ? sign_mask () : val[i];
+}
+
+/* Set the number of host wide ints actually represented within the
+   wide int.  */
+
+void
+wide_int::set_len (unsigned int l)
+{
+  gcc_assert (l <= (2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT));
+  len = l;
+}
+
+/* Set the bitsize of the wide int.  */
+
+void
+wide_int::set_bitsize (unsigned int bs)
+{
+  bitsize = bs;
+}
+
+/* Set the precision of the wide int.  */
+
+void
+wide_int::set_precision (unsigned int prec)
+{
+  precision = prec;
+}
+
+/* Get a reference to a particular element of the wide int.  Does not
+   check I against len as during construction we might want to set len
+   after creating the value.  */
+
+HOST_WIDE_INT&
+wide_int::elt_ref (unsigned int i)
+{
+  /* We check maximal size, not len.  */
+  gcc_assert (i < MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT); 
+
+  return val[i];
+}
+
+/* Get a reference to a particular element of the wide int as an
+   unsigned quantity.  Does not check I against len as during
+   construction we might want to set len after creating the value.  */
+
+unsigned HOST_WIDE_INT&
+wide_int::uelt_ref (unsigned int i)
+{
+  return *(unsigned HOST_WIDE_INT *)&elt_ref (i);
+}
+
+/* Get a reference to a particular element of the wide int as a
+   constant unsigned quantity.  Does not check I against len as during
+   construction we might want to set len after creating the value.  */
+
+const unsigned HOST_WIDE_INT&
+wide_int::uelt_ref (unsigned int i) const
+{
+  /* We check maximal size, not len.  */
+  gcc_assert (i < MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT); 
+
+  return *(const unsigned HOST_WIDE_INT *)&val[i];
+}
+
+/* Return true if THIS is -1.  */
+
+bool
+wide_int::minus_one_p () const
+{
+  return len == 1 && val[0] == (HOST_WIDE_INT)-1;
+}
+
+/* Return true if THIS is 0.  */
+
+bool
+wide_int::zero_p () const
+{
+  return len == 1 && val[0] == 0;
+}
+
+/* Return true if THIS is 1.  */
+
+bool
+wide_int::one_p () const
+{
+  return len == 1 && val[0] == 1;
+}
+
+/* Return true if THIS is negative.  */
+
+bool
+wide_int::neg_p () const
+{
+  return sign_mask () != 0;
+}
+
+/* Return true if THIS is not equal to OP1. */ 
+
+bool
+wide_int::operator != (const wide_int &op1) const
+{
+  return !(*this == op1);
+}  
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::gt_p (HOST_WIDE_INT op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return gts_p (op1);
+  else
+    return gtu_p (op1);
+}  
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::gt_p (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return op1.lts_p (*this);
+  else
+    return op1.ltu_p (*this);
+}  
+
+/* Return true if THIS is signed greater than OP1.  */
+
+bool
+wide_int::gts_p (const wide_int &op1) const
+{
+  return op1.lts_p (*this);
+}  
+
+/* Return true if THIS is unsigned greater than OP1.  */
+
+bool
+wide_int::gtu_p (const wide_int &op1) const
+{
+  return op1.ltu_p (*this);
+}  
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::lt_p (HOST_WIDE_INT op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (op1);
+  else
+    return ltu_p (op1);
+}  
+
+/* Return -1 0 or 1 depending on how THIS compares with OP1.  Signness
+   is indicated by OP.  */
+
+int
+wide_int::cmp (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return cmps (op1);
+  else
+    return cmpu (op1);
+}  
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::lt_p (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (op1);
+  else
+    return ltu_p (op1);
+}  
+
+/* Return the signed or unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::min (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return lts_p (op1) ? (*this) : op1;
+  else
+    return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed or unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::max (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return gts_p (op1) ? (*this) : op1;
+  else
+    return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed min of THIS and OP1. */
+
+wide_int
+wide_int::smin (const wide_int &op1) const
+{
+  return lts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed max of THIS and OP1. */
+
+wide_int
+wide_int::smax (const wide_int &op1) const
+{
+  return gts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::umin (const wide_int &op1) const
+{
+  return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::umax (const wide_int &op1) const
+{
+  return gtu_p (op1) ? (*this) : op1;
+}  
+
+
+/* Return true if THIS fits in a HOST_WIDE_INT with no loss of
+   precision.  */
+
+bool
+wide_int::fits_shwi_p () const
+{
+  return len == 1;
+}
+
+/* Return true if THIS fits in an unsigned HOST_WIDE_INT with no loss
+   of precision.  */
+
+bool
+wide_int::fits_uhwi_p () const
+{
+  return len == 1 
+    || (len == 2 && val[1] == 0);
+}
+
+/* Return THIS extended to PREC.  The signness of the extension is
+   specified by OP.  */
+
+wide_int 
+wide_int::ext (unsigned int prec, SignOp z) const
+{
+  if (z == UNSIGNED)
+    return zext (prec);
+  else
+    return sext (prec);
+}
+
+/* Return THIS extended to the precision of MODE.  The signness of the
+   extension is specified by OP.  The bitsize and precision of the
+   result is that same as THIS.  */
+
+wide_int 
+wide_int::ext (enum machine_mode mode, SignOp z) const
+{
+  if (z == UNSIGNED)
+    return zext (mode);
+  else
+    return sext (mode);
+}
+
+/* Return THIS extended to the precision of TYPE.  The signness of the
+   extension is specified by the sign of TYPE. The bitsize and
+   precision of the result is that same as THIS.  */
+
+wide_int 
+wide_int::ext (const_tree type) const
+{
+  if (TYPE_UNSIGNED (type))
+    return zext (TYPE_PRECISION (type));
+  else
+    return sext (TYPE_PRECISION (type));
+}
+
+/* Return THIS sign extended to the precision of MODE. The bitsize and
+   precision of the result is that same as THIS.  */
+
+wide_int 
+wide_int::sext (enum machine_mode mode) const
+{
+  return sext (GET_MODE_PRECISION (mode));
+}
+
+/* Return THIS zero extended to the precision of MODE. The bitsize and
+   precision of the result is that same as THIS.  */
+
+wide_int 
+wide_int::zext (enum machine_mode mode) const
+{
+  return zext (GET_MODE_PRECISION (mode));
+}
+
+/* Return THIS forced to the bitsize and precision of TYPE.  If this
+   is extension, the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (enum machine_mode mode, SignOp sgn) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (bitsize, prec, sgn);
+}
+
+/* Return THIS forced to the bitsize, precision and sign of TYPE.  If
+   this is extension, the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (const_tree type) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+  SignOp sgn = TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED;
+
+  return force_to_size (bitsize, prec, sgn);
+}
+
+/* Return THIS zero extended to the bitsize and precision of TYPE but
+   extends using SGN.  If this is extension, the sign is set by
+   SGN. */
+
+wide_int 
+wide_int::force_to_size (const_tree type, SignOp sgn) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (bitsize, prec, sgn);
+}
+
+/* Return THIS forced to the bitsize and precision of TYPE.  If this
+   is extension, it is signed. */
+
+wide_int 
+wide_int::sforce_to_size (enum machine_mode mode) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (bitsize, prec, SIGNED);
+}
+
+/* Return THIS zero extended to the bitsize and precision of TYPE but
+   extends using SGN.  If this is extension, it is signed. */
+
+wide_int 
+wide_int::sforce_to_size (const_tree type) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (bitsize, prec, SIGNED);
+}
+
+/* Return THIS forced to the bitsize and precision of TYPE.  If this
+   is extension, it is unsigned. */
+
+wide_int 
+wide_int::zforce_to_size (enum machine_mode mode) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (bitsize, prec, UNSIGNED);
+}
+
+/* Return THIS zero extended to the bitsize and precision of TYPE but
+   extends using SGN.  If this is extension, it is unsigned. */
+
+wide_int 
+wide_int::zforce_to_size (const_tree type) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (bitsize, prec, UNSIGNED);
+}
+
+/* Signed multiply THIS and OP1.  The result is the same precision as
+   the operands.  OVERFLOW is set true if the result overflows.  */
+
+wide_int
+wide_int::smul (const wide_int &x, bool *overflow) const
+{
+  return mul (x, SIGNED, overflow);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is the same precision
+   as the operands.  OVERFLOW is set true if the result overflows.  */
+
+wide_int
+wide_int::umul (const wide_int &x, bool *overflow) const
+{
+  return mul (x, UNSIGNED, overflow);
+}
+
+/* Signed multiply THIS and OP1.  The result is twice the precision as
+   the operands.  */
+
+wide_int
+wide_int::smul_full (const wide_int &x) const
+{
+  return mul_full (x, SIGNED);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is twice the precision
+   as the operands.  */
+
+wide_int
+wide_int::umul_full (const wide_int &x) const
+{
+  return mul_full (x, UNSIGNED);
+}
+
+/* Signed divide with truncation of result.  */
+
+wide_int
+wide_int::sdiv_trunc (const wide_int &divisor) const
+{
+  return div_trunc (divisor, SIGNED);
+}
+
+/* Unsigned divide with truncation of result.  */
+
+wide_int
+wide_int::udiv_trunc (const wide_int &divisor) const
+{
+  return div_trunc (divisor, UNSIGNED);
+}
+
+/* Unsigned divide with floor truncation of result.  */
+
+wide_int
+wide_int::udiv_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return div_floor (divisor, UNSIGNED, &overflow);
+}
+
+/* Signed divide with floor truncation of result.  */
+
+wide_int
+wide_int::sdiv_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return div_floor (divisor, SIGNED, &overflow);
+}
+
+/* Signed divide/mod with truncation of result.  */
+
+wide_int
+wide_int::sdivmod_trunc (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_trunc (divisor, mod, SIGNED);
+}
+
+/* Unsigned divide/mod with truncation of result.  */
+
+wide_int
+wide_int::udivmod_trunc (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_trunc (divisor, mod, UNSIGNED);
+}
+
+/* Signed divide/mod with floor truncation of result.  */
+
+wide_int
+wide_int::sdivmod_floor (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_floor (divisor, mod, SIGNED);
+}
+
+/* Signed mod with truncation of result.  */
+
+wide_int
+wide_int::smod_trunc (const wide_int &divisor) const
+{
+  return mod_trunc (divisor, SIGNED);
+}
+
+/* Unsigned mod with truncation of result.  */
+
+wide_int
+wide_int::umod_trunc (const wide_int &divisor) const
+{
+  return mod_trunc (divisor, UNSIGNED);
+}
+
+/* Unsigned mod with floor truncation of result.  */
+
+wide_int
+wide_int::umod_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return mod_floor (divisor, UNSIGNED, &overflow);
+}
+
+/* Right shift THIS by Y.  SGN indicates the sign.  Z indicates the
+   truncation option.  */
+
+wide_int
+wide_int::rshift (const wide_int &y, SignOp sgn, ShiftOp z) const
+{
+  if (sgn == UNSIGNED)
+    return rshiftu (y, z);
+  else
+    return rshifts (y, z);
+}
+
+/* tree related routines.  */
+
+extern tree wide_int_to_tree (tree type, const wide_int &cst);
+extern tree wide_int_to_infinite_tree (tree type, const wide_int &cst, 
+				       unsigned int prec);
+extern tree force_fit_type_wide (tree, const wide_int &, int, bool);
+extern wide_int mem_ref_offset (const_tree);
+
+/* Conversion to and from GMP integer representations.  */
+
+void mpz_set_wide_int (mpz_t, wide_int, bool);
+wide_int mpz_get_wide_int (const_tree, mpz_t, bool);
+#endif /* GENERATOR FILE */
+
+#endif /* WIDE_INT_H */

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch
  2012-10-06  0:14                                 ` patch to fix constant math - first small patch Joseph S. Myers
  2012-10-08 19:25                                   ` Kenneth Zadeck
@ 2012-11-08 17:37                                   ` Kenneth Zadeck
  2013-02-27  0:23                                   ` patch to fix constant math - first small patch - patch ping for the next stage 1 Kenneth Zadeck
  2 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-11-08 17:37 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Richard Guenther, Mike Stump, gcc-patches, rdsandiford

[-- Attachment #1: Type: text/plain, Size: 538 bytes --]

Joseph,

Here is a revised patch with the change you asked for.  There have been 
no other comments.   May I commit it?

Kenny


On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>
>> +# define HOST_HALF_WIDE_INT_PRINT "h"
> This may cause problems on hosts not supporting %hd (MinGW?), and there's
> no real need for using "h" here given the promotion of short to int; you
> can just use "" (rather than e.g. needing special handling in xm-mingw32.h
> like is done for HOST_LONG_LONG_FORMAT).
>


[-- Attachment #2: p1-2.diff --]
[-- Type: text/x-patch, Size: 4057 bytes --]

diff --git a/gcc/hwint.h b/gcc/hwint.h
index ca47148..87371b5 100644
--- a/gcc/hwint.h
+++ b/gcc/hwint.h
@@ -77,6 +77,40 @@ extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1];
 # endif
 #endif
 
+/* Print support for half a host wide int.  */
+#define HOST_BITS_PER_HALF_WIDE_INT (HOST_BITS_PER_WIDE_INT / 2)
+#if HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_LONG
+# define HOST_HALF_WIDE_INT long
+# define HOST_HALF_WIDE_INT_PRINT HOST_LONG_FORMAT
+# define HOST_HALF_WIDE_INT_PRINT_C "L"
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_INT
+# define HOST_HALF_WIDE_INT int
+# define HOST_HALF_WIDE_INT_PRINT ""
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_SHORT
+# define HOST_HALF_WIDE_INT short
+# define HOST_HALF_WIDE_INT_PRINT ""
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#else
+#error Please add support for HOST_HALF_WIDE_INT
+#endif
+
+
 #define HOST_WIDE_INT_1 HOST_WIDE_INT_C(1)
 
 /* This is a magic identifier which allows GCC to figure out the type
@@ -94,9 +128,13 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
 # if HOST_BITS_PER_WIDE_INT == 64
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%016" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%016" HOST_LONG_FORMAT "x"
 # else
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%08" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%08" HOST_LONG_FORMAT "x"
 # endif
 #else
 # define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT
@@ -104,6 +142,8 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
   /* We can assume that 'long long' is at least 64 bits.  */
 # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
     "0x%" HOST_LONG_LONG_FORMAT "x%016" HOST_LONG_LONG_FORMAT "x"
+# define HOST_WIDE_INT_PRINT_PADDED_HEX \
+    "%016" HOST_LONG_LONG_FORMAT "x"
 #endif /* HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG */
 
 #define HOST_WIDE_INT_PRINT_DEC "%" HOST_WIDE_INT_PRINT "d"
@@ -277,4 +317,32 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT);
 
+/* Sign extend SRC starting from PREC.  */
+
+static inline HOST_WIDE_INT
+sext_hwi (HOST_WIDE_INT src, int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    {
+      int shift = HOST_BITS_PER_WIDE_INT - (prec & (HOST_BITS_PER_WIDE_INT - 1));
+      return (src << shift) >> shift;
+    }
+}
+
+/* Zero extend SRC starting from PREC.  */
+
+static inline HOST_WIDE_INT
+zext_hwi (HOST_WIDE_INT src, int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    return src & (((HOST_WIDE_INT)1
+		   << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
+}
+
+
+
 #endif /* ! GCC_HWINT_H */

[-- Attachment #3: p1-1.clog --]
[-- Type: text/plain, Size: 389 bytes --]

2012-10-5  Kenneth Zadeck <zadeck@naturalbridge.com>

	* hwint.h (HOST_BITS_PER_HALF_WIDE_INT, HOST_HALF_WIDE_INT,
	HOST_HALF_WIDE_INT_PRINT, HOST_HALF_WIDE_INT_PRINT_C,
	HOST_HALF_WIDE_INT_PRINT_DEC, HOST_HALF_WIDE_INT_PRINT_DEC_C,
	HOST_HALF_WIDE_INT_PRINT_UNSIGNED, HOST_HALF_WIDE_INT_PRINT_HEX,
	HOST_HALF_WIDE_INT_PRINT_HEX_PURE): New symbols.
	(sext_hwi, zext_hwi): New functions.
	

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - second small patch
  2012-10-08  9:07                                   ` patch to fix constant math - second " Richard Guenther
@ 2012-11-08 18:14                                     ` Kenneth Zadeck
  2012-11-26 15:31                                       ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-11-08 18:14 UTC (permalink / raw)
  To: Richard Guenther; +Cc: Mike Stump, gcc-patches, rdsandiford

[-- Attachment #1: Type: text/plain, Size: 666 bytes --]

I have added the proper doc.  OK to commit?

Kenny


On 10/08/2012 05:06 AM, Richard Guenther wrote:
> On Sat, Oct 6, 2012 at 12:48 AM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> This patch adds machinery to genmodes.c so that largest possible sizes of
>> various data structures can be determined at gcc build time.  These
>> functions create 3 symbols that are available in insn-modes.h:
>> MAX_BITSIZE_MODE_INT - the bitsize of the largest int.
>> MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int.
>> MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int.
> Ok.  Please document these macros in rtl.texi.
>
> Richard.


[-- Attachment #2: p2-2.clog --]
[-- Type: text/plain, Size: 292 bytes --]

2012-11-8  Kenneth Zadeck <zadeck@naturalbridge.com>

   	* genmodes.c (emit_max_int): New function.
	(emit_insn_modes_h): Added call to emit_max_function.
	* doc/rtl.texi (MAX_BITSIZE_MODE_INT, MAX_BITSIZE_MODE_PARTIAL_INT,
	MAX_BITSIZE_MODE_ANY_INT, MAX_BITSIZE_MODE_ANY_MODE): Added doc.	

[-- Attachment #3: p2-2.diff --]
[-- Type: text/x-patch, Size: 3378 bytes --]

diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 07c480d..6842cb8 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -1458,6 +1458,28 @@ Returns the number of units contained in a mode, i.e.,
 Returns the narrowest mode in mode class @var{c}.
 @end table
 
+The following 4 variables are defined on every target.   They can be
+used to allocate buffers that are guaranteed to be large enough to
+hold any value that can be represented on the target.   
+
+@table @code
+@findex MAX_BITSIZE_MODE_INT
+@item MAX_BITSIZE_MODE_INT
+The bitsize of the largest integer mode defined on the target.
+
+@findex MAX_BITSIZE_MODE_PARTIAL_INT
+@item MAX_BITSIZE_MODE_PARTIAL_INT
+The bitsize of the largest partial integer mode defined on the target.
+
+@findex MAX_BITSIZE_MODE_ANY_INT
+@item MAX_BITSIZE_MODE_ANY_INT
+The maximum of MAX_BITSIZE_MODE_INT and MAX_BITSIZE_MODE_PARTIAL_INT.
+
+@findex MAX_BITSIZE_MODE_ANY_MODE
+@item MAX_BITSIZE_MODE_ANY_MODE
+The bitsize of the largest mode on the target.   
+@end table
+
 @findex byte_mode
 @findex word_mode
 The global variables @code{byte_mode} and @code{word_mode} contain modes
diff --git a/gcc/genmodes.c b/gcc/genmodes.c
index d0095c3..3e63cc7 100644
--- a/gcc/genmodes.c
+++ b/gcc/genmodes.c
@@ -849,6 +849,38 @@ calc_wider_mode (void)
 
 #define print_closer() puts ("};")
 
+/* Compute the max bitsize of some of the classes of integers.  It may
+   be that there are needs for the other integer classes, and this
+   code is easy to extend.  */
+static void
+emit_max_int (void)
+{
+  unsigned int max, mmax;
+  struct mode_data *i;
+  int j;
+
+  puts ("");
+  for (max = 1, i = modes[MODE_INT]; i; i = i->next)
+    if (max < i->bytesize)
+	max = i->bytesize;
+  printf ("#define MAX_BITSIZE_MODE_INT %d*BITS_PER_UNIT\n", max);
+  mmax = max;
+  for (max = 1, i = modes[MODE_PARTIAL_INT]; i; i = i->next)
+    if (max < i->bytesize)
+	max = i->bytesize;
+  printf ("#define MAX_BITSIZE_MODE_PARTIAL_INT %d*BITS_PER_UNIT\n", max);
+  if (max > mmax)
+    mmax = max;
+  printf ("#define MAX_BITSIZE_MODE_ANY_INT %d*BITS_PER_UNIT\n", mmax);
+
+  mmax = 0;
+  for (j = 0; j < MAX_MODE_CLASS; j++)
+    for (i = modes[j]; i; i = i->next)
+      if (mmax < i->bytesize)
+	mmax = i->bytesize;
+  printf ("#define MAX_BITSIZE_MODE_ANY_MODE %d*BITS_PER_UNIT\n", mmax);
+}
+
 static void
 emit_insn_modes_h (void)
 {
@@ -913,6 +945,7 @@ enum machine_mode\n{");
 #endif
   printf ("#define CONST_MODE_IBIT%s\n", adj_ibit ? "" : " const");
   printf ("#define CONST_MODE_FBIT%s\n", adj_fbit ? "" : " const");
+  emit_max_int ();
   puts ("\
 \n\
 #endif /* insn-modes.h */");
diff --git a/gcc/machmode.def b/gcc/machmode.def
index 631015f..7186cb4 100644
--- a/gcc/machmode.def
+++ b/gcc/machmode.def
@@ -180,8 +180,11 @@ RANDOM_MODE (BLK);
 FRACTIONAL_INT_MODE (BI, 1, 1);
 
 /* Basic integer modes.  We go up to TI in generic code (128 bits).
-   The name OI is reserved for a 256-bit type (needed by some back ends).
-   FIXME TI shouldn't be generically available either.  */
+   TImode is needed here because the some front ends now genericly
+   support __int128.  If the front ends decide to generically support
+   larger types, then corresponding modes must be added here.  The
+   name OI is reserved for a 256-bit type (needed by some back ends).
+    */
 INT_MODE (QI, 1);
 INT_MODE (HI, 2);
 INT_MODE (SI, 4);

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - third small patch
  2012-10-08 19:43                                       ` Richard Sandiford
  2012-10-09 15:10                                         ` patch to fix constant math - 4th patch - the wide-int class Kenneth Zadeck
  2012-10-09 18:51                                         ` patch to fix constant math - patch 5 - the rest of the rtl stuff Kenneth Zadeck
@ 2012-11-09 13:22                                         ` Kenneth Zadeck
  2 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-11-09 13:22 UTC (permalink / raw)
  To: Richard Guenther, Mike Stump, gcc-patches, rdsandiford

[-- Attachment #1: Type: text/plain, Size: 1877 bytes --]

This patch is an updated version of my patch 3 with all of richard 
sandiford's comments resolved.

Richi had approved it before he went on vacation.

Committed as revision 193360.

Kenny


On 10/08/2012 03:42 PM, Richard Sandiford wrote:
> Kenneth Zadeck <zadeck@naturalbridge.com> writes:
>> diff --git a/gcc/combine.c b/gcc/combine.c
>> index 4e0a579..b531305 100644
>> --- a/gcc/combine.c
>> +++ b/gcc/combine.c
>> @@ -2617,16 +2617,19 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
>>        constant.  */
>>     if (i1 == 0
>>         && (temp = single_set (i2)) != 0
>> -      && (CONST_INT_P (SET_SRC (temp))
>> -	  || CONST_DOUBLE_AS_INT_P (SET_SRC (temp)))
>> +      && CONST_SCALAR_INT_P (SET_SRC (temp))
>>         && GET_CODE (PATTERN (i3)) == SET
>> -      && (CONST_INT_P (SET_SRC (PATTERN (i3)))
>> -	  || CONST_DOUBLE_AS_INT_P (SET_SRC (PATTERN (i3))))
>> +      && CONST_SCALAR_INT_P (SET_SRC (PATTERN (i3)))
>>         && reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp)))
>>       {
>>         rtx dest = SET_DEST (PATTERN (i3));
>>         int offset = -1;
>>         int width = 0;
>> +
>> +      /* There are not explicit tests to make sure that this is not a
>> +	 float, but there is code here that would not be correct if it
>> +	 was.  */
>> +      gcc_assert (GET_MODE_CLASS (GET_MODE (SET_SRC (temp))) != MODE_FLOAT);
> No need for this assert: CONST_SCALAR_INT_P (SET_SRC (temp)) should cover it.
>
>> @@ -1009,9 +1007,7 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, enum machine_mode memmode)
>>   static rtx
>>   wrap_constant (enum machine_mode mode, rtx x)
>>   {
>> -  if (!CONST_INT_P (x)
>> -      && GET_CODE (x) != CONST_FIXED
>> -      && !CONST_DOUBLE_AS_INT_P (x))
>> +  if ((!CONST_SCALAR_INT_P (x)) && GET_CODE (x) != CONST_FIXED)
> Redundant brackets.
>
> Looks good to me otherwise, thanks.
>
> Richard


[-- Attachment #2: p3-2.clog --]
[-- Type: text/plain, Size: 847 bytes --]

2012-11-09  Kenneth Zadeck <zadeck@naturalbridge.com>

	* rtl.h (CONST_SCALAR_INT_P): New macro.
   	* cfgexpand.c (expand_debug_locations): Changed to use
	CONST_SCALAR_INT_P macro.
	* combine.c (try_combine, subst, make_extraction,
	gen_lowpart_for_combine): Ditto.
	* cselib.c (entry_and_rtx_equal_p, rtx_equal_for_cselib_1): Ditto.
	* dwarf2out.c (loc_descriptor): Ditto.
	* emit-rtl.c (gen_lowpart_common): Ditto.
	* ira-costs.c (record_reg_classes, record_address_regs): Ditto.
	* ira-lives.c (single_reg_class): Ditto.
	* recog.c (simplify_while_replacing, asm_operand_ok,
	constrain_operands): Ditto.
	* reload.c (find_reloads): Ditto.
	* simplify-rtx.c (simplify_unary_operation_1,
	simplify_const_unary_operation, simplify_binary_operation_1,
	simplify_const_binary_operation, simplify_relational_operation_1,
	simplify_subreg): Ditto.


[-- Attachment #3: p3-2.diff --]
[-- Type: text/x-patch, Size: 15476 bytes --]

diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index e501b4b..0bd9d1d 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -3647,9 +3647,8 @@ expand_debug_locations (void)
 
 	    gcc_assert (mode == GET_MODE (val)
 			|| (GET_MODE (val) == VOIDmode
-			    && (CONST_INT_P (val)
+			    && (CONST_SCALAR_INT_P (val)
 				|| GET_CODE (val) == CONST_FIXED
-				|| CONST_DOUBLE_AS_INT_P (val) 
 				|| GET_CODE (val) == LABEL_REF)));
 	  }
 
diff --git a/gcc/combine.c b/gcc/combine.c
index 00719a7..5e85f77 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -2619,17 +2619,15 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
      constant.  */
   if (i1 == 0
       && (temp = single_set (i2)) != 0
-      && (CONST_INT_P (SET_SRC (temp))
-	  || CONST_DOUBLE_AS_INT_P (SET_SRC (temp)))
+      && CONST_SCALAR_INT_P (SET_SRC (temp))
       && GET_CODE (PATTERN (i3)) == SET
-      && (CONST_INT_P (SET_SRC (PATTERN (i3)))
-	  || CONST_DOUBLE_AS_INT_P (SET_SRC (PATTERN (i3))))
+      && CONST_SCALAR_INT_P (SET_SRC (PATTERN (i3)))
       && reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp)))
     {
       rtx dest = SET_DEST (PATTERN (i3));
       int offset = -1;
       int width = 0;
-
+      
       if (GET_CODE (dest) == ZERO_EXTRACT)
 	{
 	  if (CONST_INT_P (XEXP (dest, 1))
@@ -5104,8 +5102,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
 	      if (GET_CODE (new_rtx) == CLOBBER && XEXP (new_rtx, 0) == const0_rtx)
 		return new_rtx;
 
-	      if (GET_CODE (x) == SUBREG
-		  && (CONST_INT_P (new_rtx) || CONST_DOUBLE_AS_INT_P (new_rtx)))
+	      if (GET_CODE (x) == SUBREG && CONST_SCALAR_INT_P (new_rtx))
 		{
 		  enum machine_mode mode = GET_MODE (x);
 
@@ -7134,7 +7131,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
       if (mode == tmode)
 	return new_rtx;
 
-      if (CONST_INT_P (new_rtx) || CONST_DOUBLE_AS_INT_P (new_rtx))
+      if (CONST_SCALAR_INT_P (new_rtx))
 	return simplify_unary_operation (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
 					 mode, new_rtx, tmode);
 
@@ -10658,8 +10655,7 @@ gen_lowpart_for_combine (enum machine_mode omode, rtx x)
   /* We can only support MODE being wider than a word if X is a
      constant integer or has a mode the same size.  */
   if (GET_MODE_SIZE (omode) > UNITS_PER_WORD
-      && ! ((CONST_INT_P (x) || CONST_DOUBLE_AS_INT_P (x))
-	    || isize == osize))
+      && ! (CONST_SCALAR_INT_P (x) || isize == osize))
     goto fail;
 
   /* X might be a paradoxical (subreg (mem)).  In that case, gen_lowpart
diff --git a/gcc/cselib.c b/gcc/cselib.c
index 1f9f97e..f610bc3 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -537,17 +537,15 @@ entry_and_rtx_equal_p (const void *entry, const void *x_arg)
   rtx x = CONST_CAST_RTX ((const_rtx)x_arg);
   enum machine_mode mode = GET_MODE (x);
 
-  gcc_assert (!CONST_INT_P (x) && GET_CODE (x) != CONST_FIXED
-	      && (mode != VOIDmode || GET_CODE (x) != CONST_DOUBLE));
+  gcc_assert (!CONST_SCALAR_INT_P (x) && GET_CODE (x) != CONST_FIXED);
 
   if (mode != GET_MODE (v->val_rtx))
     return 0;
 
   /* Unwrap X if necessary.  */
   if (GET_CODE (x) == CONST
-      && (CONST_INT_P (XEXP (x, 0))
-	  || GET_CODE (XEXP (x, 0)) == CONST_FIXED
-	  || GET_CODE (XEXP (x, 0)) == CONST_DOUBLE))
+      && (CONST_SCALAR_INT_P (XEXP (x, 0))
+	  || GET_CODE (XEXP (x, 0)) == CONST_FIXED))
     x = XEXP (x, 0);
 
   /* We don't guarantee that distinct rtx's have different hash values,
@@ -1030,9 +1028,7 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, enum machine_mode memmode)
 static rtx
 wrap_constant (enum machine_mode mode, rtx x)
 {
-  if (!CONST_INT_P (x) 
-      && GET_CODE (x) != CONST_FIXED
-      && !CONST_DOUBLE_AS_INT_P (x))
+  if (!CONST_SCALAR_INT_P (x) && GET_CODE (x) != CONST_FIXED)
     return x;
   gcc_assert (mode != VOIDmode);
   return gen_rtx_CONST (mode, x);
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 7dd1f24..ae87df1 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -13023,8 +13023,8 @@ loc_descriptor (rtx rtl, enum machine_mode mode,
 
     case CONST:
       if (mode == VOIDmode
-	  || GET_CODE (XEXP (rtl, 0)) == CONST_INT
-	  || GET_CODE (XEXP (rtl, 0)) == CONST_DOUBLE
+	  || CONST_SCALAR_INT_P (XEXP (rtl, 0))
+	  || CONST_DOUBLE_AS_FLOAT_P (XEXP (rtl, 0))
 	  || GET_CODE (XEXP (rtl, 0)) == CONST_VECTOR)
 	{
 	  loc_result = loc_descriptor (XEXP (rtl, 0), mode, initialized);
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index cb23d5a..95bbfa7 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1249,7 +1249,7 @@ gen_lowpart_common (enum machine_mode mode, rtx x)
     }
   else if (GET_CODE (x) == SUBREG || REG_P (x)
 	   || GET_CODE (x) == CONCAT || GET_CODE (x) == CONST_VECTOR
-	   || CONST_DOUBLE_P (x) || CONST_INT_P (x))
+	   || CONST_DOUBLE_AS_FLOAT_P (x) || CONST_SCALAR_INT_P (x))
     return simplify_gen_subreg (mode, x, innermode, offset);
 
   /* Otherwise, we can't do this.  */
diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c
index 034eff8..b2060ef 100644
--- a/gcc/ira-costs.c
+++ b/gcc/ira-costs.c
@@ -667,7 +667,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
 		  break;
 
 		case 's':
-		  if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op)) 
+		  if (CONST_SCALAR_INT_P (op)) 
 		    break;
 
 		case 'i':
@@ -677,7 +677,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
 		  break;
 
 		case 'n':
-		  if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op)) 
+		  if (CONST_SCALAR_INT_P (op)) 
 		    win = 1;
 		  break;
 
@@ -1068,7 +1068,7 @@ record_address_regs (enum machine_mode mode, addr_space_t as, rtx x,
 
 	/* If the second operand is a constant integer, it doesn't
 	   change what class the first operand must be.  */
-	else if (code1 == CONST_INT || code1 == CONST_DOUBLE)
+	else if (CONST_SCALAR_INT_P (arg1))
 	  record_address_regs (mode, as, arg0, context, PLUS, code1, scale);
 	/* If the second operand is a symbolic constant, the first
 	   operand must be an index register.  */
diff --git a/gcc/ira-lives.c b/gcc/ira-lives.c
index 78206f3..f8a0fa1 100644
--- a/gcc/ira-lives.c
+++ b/gcc/ira-lives.c
@@ -779,22 +779,16 @@ single_reg_class (const char *constraints, rtx op, rtx equiv_const)
 	  break;
 
 	case 'n':
-	  if (CONST_INT_P (op)
-	      || CONST_DOUBLE_AS_INT_P (op)
-	      || (equiv_const != NULL_RTX
-		  && (CONST_INT_P (equiv_const)
-		      || CONST_DOUBLE_AS_INT_P (equiv_const))))
+	  if (CONST_SCALAR_INT_P (op)
+	      || (equiv_const != NULL_RTX && CONST_SCALAR_INT_P (equiv_const)))
 	    return NO_REGS;
 	  break;
 
 	case 's':
-	  if ((CONSTANT_P (op) 
-	       && !CONST_INT_P (op) 
-	       && !CONST_DOUBLE_AS_INT_P (op))
+	  if ((CONSTANT_P (op) && !CONST_SCALAR_INT_P (op))
 	      || (equiv_const != NULL_RTX
 		  && CONSTANT_P (equiv_const)
-		  && !CONST_INT_P (equiv_const)
-		  && !CONST_DOUBLE_AS_INT_P (equiv_const)))
+		  && !CONST_SCALAR_INT_P (equiv_const)))
 	    return NO_REGS;
 	  break;
 
diff --git a/gcc/recog.c b/gcc/recog.c
index 3a53455..ee68e30 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -578,8 +578,7 @@ simplify_while_replacing (rtx *loc, rtx to, rtx object,
 			 (PLUS, GET_MODE (x), XEXP (x, 0), XEXP (x, 1)), 1);
       break;
     case MINUS:
-      if (CONST_INT_P (XEXP (x, 1))
-	  || CONST_DOUBLE_AS_INT_P (XEXP (x, 1)))
+      if (CONST_SCALAR_INT_P (XEXP (x, 1)))
 	validate_change (object, loc,
 			 simplify_gen_binary
 			 (PLUS, GET_MODE (x), XEXP (x, 0),
@@ -1730,7 +1729,7 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
 	  break;
 
 	case 's':
-	  if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+	  if (CONST_SCALAR_INT_P (op))
 	    break;
 	  /* Fall through.  */
 
@@ -1740,7 +1739,7 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
 	  break;
 
 	case 'n':
-	  if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+	  if (CONST_SCALAR_INT_P (op))
 	    result = 1;
 	  break;
 
@@ -2596,7 +2595,7 @@ constrain_operands (int strict)
 		break;
 
 	      case 's':
-		if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+		if (CONST_SCALAR_INT_P (op))
 		  break;
 	      case 'i':
 		if (CONSTANT_P (op))
@@ -2604,7 +2603,7 @@ constrain_operands (int strict)
 		break;
 
 	      case 'n':
-		if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
+		if (CONST_SCALAR_INT_P (op))
 		  win = 1;
 		break;
 
diff --git a/gcc/reload.c b/gcc/reload.c
index 91521b1..aea2072 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -3437,7 +3437,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
 		    break;
 
 		  case 's':
-		    if (CONST_INT_P (operand) || CONST_DOUBLE_AS_INT_P (operand))
+		    if (CONST_SCALAR_INT_P (operand))
 		      break;
 		  case 'i':
 		    if (CONSTANT_P (operand)
@@ -3446,7 +3446,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
 		    break;
 
 		  case 'n':
-		    if (CONST_INT_P (operand) || CONST_DOUBLE_AS_INT_P (operand))
+		    if (CONST_SCALAR_INT_P (operand))
 		      win = 1;
 		    break;
 
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 4ee27d9..16004e2c 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -432,6 +432,10 @@ struct GTY((variable_size)) rtvec_def {
 #define CONST_DOUBLE_AS_INT_P(X) \
   (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == VOIDmode)
 
+/* Predicate yielding true iff X is an rtx for a integer const.  */
+#define CONST_SCALAR_INT_P(X) \
+  (CONST_INT_P (X) || CONST_DOUBLE_AS_INT_P (X))
+
 /* Predicate yielding true iff X is an rtx for a double-int.  */
 #define CONST_DOUBLE_AS_FLOAT_P(X) \
   (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode)
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 6c50d30..18223a8 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -934,8 +934,8 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
 	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
 	{
 	  /* (neg (plus A C)) is simplified to (minus -C A).  */
-	  if (CONST_INT_P (XEXP (op, 1))
-	      || CONST_DOUBLE_P (XEXP (op, 1)))
+	  if (CONST_SCALAR_INT_P (XEXP (op, 1))
+	      || CONST_DOUBLE_AS_FLOAT_P (XEXP (op, 1)))
 	    {
 	      temp = simplify_unary_operation (NEG, mode, XEXP (op, 1), mode);
 	      if (temp)
@@ -1473,7 +1473,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  gcc_assert (GET_MODE_INNER (mode) == GET_MODE_INNER
 						(GET_MODE (op)));
       }
-      if (CONST_INT_P (op) || CONST_DOUBLE_P (op)
+      if (CONST_SCALAR_INT_P (op) || CONST_DOUBLE_AS_FLOAT_P (op)
 	  || GET_CODE (op) == CONST_VECTOR)
 	{
           int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
@@ -1526,7 +1526,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
      check the wrong mode (input vs. output) for a conversion operation,
      such as FIX.  At some point, this should be simplified.  */
 
-  if (code == FLOAT && (CONST_DOUBLE_AS_INT_P (op) || CONST_INT_P (op)))
+  if (code == FLOAT && CONST_SCALAR_INT_P (op))
     {
       HOST_WIDE_INT hv, lv;
       REAL_VALUE_TYPE d;
@@ -1540,8 +1540,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       d = real_value_truncate (mode, d);
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
-  else if (code == UNSIGNED_FLOAT
-	   && (CONST_DOUBLE_AS_INT_P (op) || CONST_INT_P (op)))
+  else if (code == UNSIGNED_FLOAT && CONST_SCALAR_INT_P (op))
     {
       HOST_WIDE_INT hv, lv;
       REAL_VALUE_TYPE d;
@@ -2232,10 +2231,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	}
 
       /* (plus (xor X C1) C2) is (xor X (C1^C2)) if C2 is signbit.  */
-      if ((CONST_INT_P (op1) || CONST_DOUBLE_AS_INT_P (op1))
+      if (CONST_SCALAR_INT_P (op1)
 	  && GET_CODE (op0) == XOR
-	  && (CONST_INT_P (XEXP (op0, 1))
-	      || CONST_DOUBLE_AS_INT_P (XEXP (op0, 1)))
+	  && CONST_SCALAR_INT_P (XEXP (op0, 1))
 	  && mode_signbit_p (mode, op1))
 	return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
 				    simplify_gen_binary (XOR, mode, op1,
@@ -2415,7 +2413,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       /* (-x - c) may be simplified as (-c - x).  */
       if (GET_CODE (op0) == NEG
-	  && (CONST_INT_P (op1) || CONST_DOUBLE_P (op1)))
+	  && (CONST_SCALAR_INT_P (op1) || CONST_DOUBLE_AS_FLOAT_P (op1)))
 	{
 	  tem = simplify_unary_operation (NEG, mode, op1, mode);
 	  if (tem)
@@ -2773,14 +2771,13 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	 return CONST0_RTX (mode);
 
       /* Canonicalize XOR of the most significant bit to PLUS.  */
-      if ((CONST_INT_P (op1) || CONST_DOUBLE_AS_INT_P (op1))
+      if (CONST_SCALAR_INT_P (op1)
 	  && mode_signbit_p (mode, op1))
 	return simplify_gen_binary (PLUS, mode, op0, op1);
       /* (xor (plus X C1) C2) is (xor X (C1^C2)) if C1 is signbit.  */
-      if ((CONST_INT_P (op1) || CONST_DOUBLE_AS_INT_P (op1))
+      if (CONST_SCALAR_INT_P (op1)
 	  && GET_CODE (op0) == PLUS
-	  && (CONST_INT_P (XEXP (op0, 1))
-	      || CONST_DOUBLE_AS_INT_P (XEXP (op0, 1)))
+	  && CONST_SCALAR_INT_P (XEXP (op0, 1))
 	  && mode_signbit_p (mode, XEXP (op0, 1)))
 	return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
 				    simplify_gen_binary (XOR, mode, op1,
@@ -3545,9 +3542,11 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	  gcc_assert (GET_MODE_INNER (mode) == op1_mode);
 
 	if ((GET_CODE (trueop0) == CONST_VECTOR
-	     || CONST_INT_P (trueop0) || CONST_DOUBLE_P (trueop0))
+	     || CONST_SCALAR_INT_P (trueop0) 
+	     || CONST_DOUBLE_AS_FLOAT_P (trueop0))
 	    && (GET_CODE (trueop1) == CONST_VECTOR
-		|| CONST_INT_P (trueop1) || CONST_DOUBLE_P (trueop1)))
+		|| CONST_SCALAR_INT_P (trueop1) 
+		|| CONST_DOUBLE_AS_FLOAT_P (trueop1)))
 	  {
 	    int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
 	    unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
@@ -3644,11 +3643,11 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
   if (VECTOR_MODE_P (mode)
       && code == VEC_CONCAT
-      && (CONST_INT_P (op0)
+      && (CONST_SCALAR_INT_P (op0)
 	  || GET_CODE (op0) == CONST_FIXED
-	  || CONST_DOUBLE_P (op0))
-      && (CONST_INT_P (op1)
-	  || CONST_DOUBLE_P (op1)
+	  || CONST_DOUBLE_AS_FLOAT_P (op0))
+      && (CONST_SCALAR_INT_P (op1)
+	  || CONST_DOUBLE_AS_FLOAT_P (op1)
 	  || GET_CODE (op1) == CONST_FIXED))
     {
       unsigned n_elts = GET_MODE_NUNITS (mode);
@@ -4674,9 +4673,8 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
   /* (eq/ne (xor x C1) C2) simplifies to (eq/ne x (C1^C2)).  */
   if ((code == EQ || code == NE)
       && op0code == XOR
-      && (CONST_INT_P (op1) || CONST_DOUBLE_AS_INT_P (op1))
-      && (CONST_INT_P (XEXP (op0, 1))
-	  || CONST_DOUBLE_AS_INT_P (XEXP (op0, 1))))
+      && CONST_SCALAR_INT_P (op1)
+      && CONST_SCALAR_INT_P (XEXP (op0, 1)))
     return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 0),
 				    simplify_gen_binary (XOR, cmp_mode,
 							 XEXP (op0, 1), op1));
@@ -5693,8 +5691,8 @@ simplify_subreg (enum machine_mode outermode, rtx op,
   if (outermode == innermode && !byte)
     return op;
 
-  if (CONST_INT_P (op)
-      || CONST_DOUBLE_P (op)
+  if (CONST_SCALAR_INT_P (op)
+      || CONST_DOUBLE_AS_FLOAT_P (op)
       || GET_CODE (op) == CONST_FIXED
       || GET_CODE (op) == CONST_VECTOR)
     return simplify_immed_subreg (outermode, op, innermode, byte);

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - second small patch
  2012-11-08 18:14                                     ` Kenneth Zadeck
@ 2012-11-26 15:31                                       ` Richard Biener
  0 siblings, 0 replies; 217+ messages in thread
From: Richard Biener @ 2012-11-26 15:31 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, rdsandiford

On Thu, Nov 8, 2012 at 7:13 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> I have added the proper doc.  OK to commit?

Ok.

Thanks,
Richard.

> Kenny
>
>
>
> On 10/08/2012 05:06 AM, Richard Guenther wrote:
>>
>> On Sat, Oct 6, 2012 at 12:48 AM, Kenneth Zadeck
>> <zadeck@naturalbridge.com> wrote:
>>>
>>> This patch adds machinery to genmodes.c so that largest possible sizes of
>>> various data structures can be determined at gcc build time.  These
>>> functions create 3 symbols that are available in insn-modes.h:
>>> MAX_BITSIZE_MODE_INT - the bitsize of the largest int.
>>> MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int.
>>> MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int.
>>
>> Ok.  Please document these macros in rtl.texi.
>>
>> Richard.
>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class.
  2012-10-31 14:25                                                                       ` Richard Biener
  2012-10-31 14:30                                                                         ` Kenneth Zadeck
  2012-11-01 22:13                                                                         ` patch to fix constant math - 8th patch - tree-vrp.c Kenneth Zadeck
@ 2012-11-30 16:46                                                                         ` Kenneth Zadeck
  2012-11-30 17:00                                                                           ` patch to fix constant math - 5th patch - the rtl level changes Kenneth Zadeck
  2013-02-27  1:59                                                                         ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Kenneth Zadeck
  3 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-11-30 16:46 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford

[-- Attachment #1: Type: text/plain, Size: 2020 bytes --]

Enclosed is the next iteration of the wide-int patch.

Many of the changes that have been suggested have been incorporated into 
this version.   The one change of note that has not is the templating of 
the storage.    This will be addressed in a separate email with a 
prototype patch.   But the short answer is that Mike and I feel that 
would be a serious mistake to go in that direction.   However, comments 
on that should be attached to that thread.

There are several major changes since the earlier version of this patch:

1) Wide-ints are now pure (const, readonly  ..).  Once they are created, 
there is now way to change them.  We had functions that exposed insides 
so to deal with some places where the construction was awkward.   We 
removed all of that in favor of having a constructor that is passed in 
an array and copies the bits into the new wide-int.

2) With the exception of the constructors from rtx and tree, there is no 
mention of rtxes or trees inside of wide-ints.  There are a large number 
of convenience calls that take a mode or a type, but these convenience 
calls only examine these parameters to get the bitsize, precision and 
sometimes the signness.

3) The implementation methods have been factored for most of the 
operations into a part that deals with integers that fit in an HWI and a 
part for those that do not.    The former are done inline in the 
wide-int.h file and typically expand into a test of the precision of the 
integer followed by a single line to do the operation.   Since the vast 
majority of constants are small, this results in a very efficient 
implementation without blowing up the code size.

4) There has been an attempt to regularize the set of calls.   All of 
the issues with the confusing sign extension calls has been addressed.

5) There are a series of calls that allow for values to be constructed 
that are larger than their natural size.   These will be used to support 
optimizations like vrp which require "infinite precision math".

Kenny


[-- Attachment #2: p4-3.diff --]
[-- Type: text/x-patch, Size: 155750 bytes --]

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 44f1e08..34a2f8b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -857,7 +857,7 @@ COMMON_TARGET_DEF_H = common/common-target-def.h \
 RTL_BASE_H = coretypes.h rtl.h rtl.def $(MACHMODE_H) reg-notes.def \
   insn-notes.def $(INPUT_H) $(REAL_H) statistics.h $(VEC_H) \
   $(FIXED_VALUE_H) alias.h $(HASHTAB_H)
-FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h
+FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h wide-int.h
 RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h
 RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H)
 READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
@@ -869,7 +869,7 @@ INTERNAL_FN_H = internal-fn.h $(INTERNAL_FN_DEF)
 TREE_H = coretypes.h tree.h all-tree.def tree.def c-family/c-common.def \
 	$(lang_tree_files) $(MACHMODE_H) tree-check.h $(BUILTINS_DEF) \
 	$(INPUT_H) statistics.h $(VEC_H) treestruct.def $(HASHTAB_H) \
-	double-int.h alias.h $(SYMTAB_H) $(FLAGS_H) \
+	double-int.h wide-int.h alias.h $(SYMTAB_H) $(FLAGS_H) \
 	$(REAL_H) $(FIXED_VALUE_H)
 REGSET_H = regset.h $(BITMAP_H) hard-reg-set.h
 BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) \
@@ -1458,6 +1458,7 @@ OBJS = \
 	varpool.o \
 	vmsdbgout.o \
 	web.o \
+	wide-int.o \
 	xcoffout.o \
 	$(out_object_file) \
 	$(EXTRA_OBJS) \
@@ -2674,6 +2675,7 @@ targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
    tree-ssa-alias.h $(TREE_FLOW_H)
 common/common-targhooks.o : common/common-targhooks.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(INPUT_H) $(TM_H) $(COMMON_TARGET_H) common/common-targhooks.h
+wide-int.o: wide-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
 
 bversion.h: s-bversion; @true
 s-bversion: BASE-VER
@@ -3906,15 +3908,16 @@ CFLAGS-gengtype-parse.o += -DGENERATOR_FILE
 build/gengtype-parse.o: $(BCONFIG_H)
 
 gengtype-state.o build/gengtype-state.o: gengtype-state.c $(SYSTEM_H) \
-  gengtype.h errors.h double-int.h version.h $(HASHTAB_H) $(OBSTACK_H) \
-  $(XREGEX_H)
+  gengtype.h errors.h double-int.h wide-int.h version.h $(HASHTAB_H)    \
+  $(OBSTACK_H) $(XREGEX_H)
 gengtype-state.o: $(CONFIG_H)
 CFLAGS-gengtype-state.o += -DGENERATOR_FILE
 build/gengtype-state.o: $(BCONFIG_H)
+wide-int.h: $(GTM_H) insn-modes.h
 
 gengtype.o build/gengtype.o : gengtype.c $(SYSTEM_H) gengtype.h 	\
-  rtl.def insn-notes.def errors.h double-int.h version.h $(HASHTAB_H) \
-  $(OBSTACK_H) $(XREGEX_H)
+  rtl.def insn-notes.def errors.h double-int.h wide-int.h version.h     \
+  $(HASHTAB_H) $(OBSTACK_H) $(XREGEX_H)
 gengtype.o: $(CONFIG_H)
 CFLAGS-gengtype.o += -DGENERATOR_FILE
 build/gengtype.o: $(BCONFIG_H)
diff --git a/gcc/wide-int.c b/gcc/wide-int.c
new file mode 100644
index 0000000..191fb17
--- /dev/null
+++ b/gcc/wide-int.c
@@ -0,0 +1,3541 @@
+/* Operations with very long integers.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hwint.h"
+#include "wide-int.h"
+#include "rtl.h"
+#include "tree.h"
+#include "dumpfile.h"
+
+// using wide_int::;
+
+/* Debugging routines.  */
+
+/* This is the maximal size of the buffer needed for dump.  */
+const int MAX_SIZE = 4 * (MAX_BITSIZE_MODE_ANY_INT / 4
+		     + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
+
+/*
+ * Internal utilities.
+ */
+
+/* Quantities to deal with values that hold half of a wide int.  Used
+   in multiply and divide.  */
+#define HALF_INT_MASK (((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1)
+
+#define BLOCK_OF(TARGET) ((TARGET) / HOST_BITS_PER_WIDE_INT)
+#define BLOCKS_NEEDED(PREC) \
+  (((PREC) + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+
+/*
+ * Conversion routines in and out of wide-int.
+ */
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  The overflow bit are set if the number was too
+   large to fit in the mode.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, unsigned int bitsize,
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT t = sext_hwi (op0, precision);
+      if (t != op0)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+  result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wh ("wide_int::from_shwi %s " HOST_WIDE_INT_PRINT_HEX ")\n",
+	      result, op0);
+#endif
+
+  return result;
+}
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  The overflow bit are set if the number was too
+   large to fit in the mode.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, unsigned int bitsize, 
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT t = zext_hwi (op0, precision);
+      if (t != op0)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && precision > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wh ("wide_int::from_uhwi %s " HOST_WIDE_INT_PRINT_HEX ")\n",
+	      result, op0);
+#endif
+
+  return result;
+}
+
+/* Create a wide_int from an array of host_wide_ints in OP1 of LEN.
+   The result has BITSIZE and PRECISION.  */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT *op1, unsigned int len, 
+		      unsigned int bitsize, unsigned int precision)
+{
+  unsigned int i;
+  wide_int result;
+  
+  result.len = len;
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  for (i=0; i < len; i++)
+    result.val[i] = op1[i];
+
+  result.canonize ();
+  return result;
+}
+
+/* Convert a double int into a wide int with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::from_double_int (double_int di, unsigned int bs, unsigned int prec)
+{
+  HOST_WIDE_INT op = di.low;
+  wide_int result;
+
+  result.bitsize = bs;
+  result.precision = prec;
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result.val[0] = sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    result.val[1] = sext_hwi (di.high, prec);
+	  else
+	    result.val[1] = di.high;
+	}
+    }
+
+  if (result.len == 2)
+    result.canonize ();
+
+  return result;
+}
+
+/* Convert a integer cst into a wide int.  */
+
+wide_int
+wide_int::from_tree (const_tree tcst)
+{
+#ifdef NEW_REP_FOR_INT_CST
+  /* This is the code once the tree level is converted.  */
+  wide_int result;
+  int i;
+
+  tree type = TREE_TYPE (tcst);
+
+  result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  result.precision = TYPE_PRECISION (type);
+  result.len = TREE_INT_CST_LEN (tcst);
+  for (i = 0; i < result.len; i++)
+    result.val[i] = TREE_INT_CST_ELT (tcst, i);
+
+  return result;
+#else
+  wide_int result;
+  tree type = TREE_TYPE (tcst);
+  unsigned int prec = TYPE_PRECISION (type);
+  HOST_WIDE_INT op = TREE_INT_CST_LOW (tcst);
+
+  result.precision = prec;
+  result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    if (TYPE_UNSIGNED (type))
+      result.val[0] = zext_hwi (op, prec);
+    else
+      result.val[0] = sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    {
+	      op = TREE_INT_CST_HIGH (tcst);
+	      if (TYPE_UNSIGNED (type))
+		result.val[1] = zext_hwi (op, prec);
+	      else
+		result.val[1] = sext_hwi (op, prec);
+	    }
+	  else
+	    result.val[1] = TREE_INT_CST_HIGH (tcst);
+	}
+      else
+	result.len = 1;
+    }
+  
+  if (result.len == 2)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      debug_whh ("wide_int:: %s = from_tree ("HOST_WIDE_INT_PRINT_HEX" "HOST_WIDE_INT_PRINT_HEX")\n",
+		 result, TREE_INT_CST_HIGH (tcst), TREE_INT_CST_LOW (tcst));
+    }
+#endif
+
+  return result;
+#endif
+}
+
+/* Convert a integer cst into a wide int expanded to BITSIZE and
+   PRECISION.  This call is used by tree passes like vrp that expect
+   that the math is done in an infinite precision style.  BITSIZE and
+   PRECISION are generally determined to be twice the largest type
+   seen in the function.  */
+
+wide_int
+wide_int::from_tree_as_infinite_precision (const_tree tcst, 
+					   unsigned int bitsize, 
+					   unsigned int precision)
+{
+  /* The plan here is to extend the value in the cst, using signed or
+     unsigned based on the type, from the precision in the type to
+     PRECISION and then canonize from there.  */
+  wide_int result;
+  tree type = TREE_TYPE (tcst);
+  unsigned int prec = TYPE_PRECISION (type);
+
+
+#ifdef NEW_REP_FOR_INT_CST
+  /* This is the code once the tree level is converted.  */
+  int i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  result.len = TREE_INT_CST_LEN (tcst);
+  for (i = 0; i < result.len; i++)
+    result.val[i] = TREE_INT_CST_ELT (tcst, i);
+
+  if (TYPE_UNSIGNED (type))
+    result = result.zext (prec);
+  else
+    result = result.sext (prec);
+
+#else
+  HOST_WIDE_INT op = TREE_INT_CST_LOW (tcst);
+
+  gcc_assert (prec <= precision);
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  result.len = 1;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result.val[0] = TYPE_UNSIGNED (type) 
+      ? zext_hwi (op, prec) : sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    {
+	      op = TREE_INT_CST_HIGH (tcst);
+	      prec -= HOST_BITS_PER_WIDE_INT;
+	      result.val[1] = TYPE_UNSIGNED (type) 
+		? zext_hwi (op, prec) : sext_hwi (op, prec);
+	      result.len = 2;
+	    }
+	  else
+	    {
+	      result.val[1] = TREE_INT_CST_HIGH (tcst);
+	      if (TYPE_UNSIGNED (type) && result.val[1] < 0)
+		{
+		  result.val[2] = 0;
+		  result.len = 2;
+		}
+	      else
+		result.len = 2;
+	    }
+	}
+      else
+	if (TYPE_UNSIGNED (type) && result.val[0] < 0)
+	  {
+	    result.val[1] = 0;
+	    result.len = 2;
+	  }
+    }
+
+#endif
+
+  return result;
+}
+
+/* Extract a constant integer from the X of type MODE.  The bits of
+   the integer are returned.  */
+
+wide_int
+wide_int::from_rtx (const_rtx x, enum machine_mode mode)
+{
+  wide_int result;
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  gcc_assert (mode != VOIDmode);
+
+  result.bitsize = GET_MODE_BITSIZE (mode);
+  result.precision = prec;
+
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+      if ((prec & (HOST_BITS_PER_WIDE_INT - 1)) != 0)
+	result.val[0] = sext_hwi (INTVAL (x), prec);
+      else
+	result.val[0] = INTVAL (x);
+      result.len = 1;
+      break;
+
+#if TARGET_SUPPORTS_WIDE_INT
+    case CONST_WIDE_INT:
+      {
+	int i;
+	result.len = CONST_WIDE_INT_NUNITS (x);
+	
+	for (i = 0; i < result.len; i++)
+	  result.val[i] = CONST_WIDE_INT_ELT (x, i);
+      }
+      break;
+#else
+    case CONST_DOUBLE:
+      result.len = 2;
+      result.val[0] = CONST_DOUBLE_LOW (x);
+      result.val[1] = CONST_DOUBLE_HIGH (x);
+      result.canonize ();
+      break;
+#endif
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return result;
+}
+
+/*
+ * Largest and smallest values in a mode.
+ */
+
+/* Produce the largest SGNed number that is represented in PREC.  The
+   resulting number is placed in a wide int of size BITSIZE and
+   PRECISION.  */
+
+wide_int
+wide_int::max_value (unsigned int prec, 
+		     unsigned int bitsize, unsigned int precision, 
+		     SignOp sgn)
+{
+  wide_int result;
+  
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned max is just all ones, for which the compressed
+	 rep is just a single HWI.  */ 
+      result.len = 1;
+      result.val[0] = (HOST_WIDE_INT)-1;
+    }
+  else
+    {
+      /* The signed max is all ones except the top bit.  This must be
+	 explicitly represented.  */
+      int i;
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      int shift = (small_prec == 0) 
+	? HOST_BITS_PER_WIDE_INT - 1 : small_prec - 1;
+
+      result.len = BLOCKS_NEEDED (prec);
+      for (i = 0; i < result.len - 1; i++)
+	result.val[i] = (HOST_WIDE_INT)-1;
+
+      result.val[result.len - 1] = ((HOST_WIDE_INT)1 << shift) - 1;
+    }
+  
+  return result;
+}
+
+/* Produce the smallest SGNed number that is represented in PREC.  The
+   resulting number is placed in a wide int of size BITSIZE and
+   PRECISION.  */
+
+wide_int
+wide_int::min_value (unsigned int prec, 
+		     unsigned int bitsize, unsigned int precision, 
+		     SignOp sgn)
+{
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned min is just all zeros, for which the compressed
+	 rep is just a single HWI.  */ 
+      wide_int result;
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = 0;
+      return result;
+    }
+  else
+    {
+      /* The signed min is all zeros except the top bit.  This must be
+	 explicitly represented.  */
+      return set_bit_in_zero (prec - 1, bitsize, precision);
+    }
+}
+
+/*
+ * Public utilities.
+ */
+
+/* Check the upper HOST_WIDE_INTs of src to see if the length can be
+   shortened.  An upper HOST_WIDE_INT is unnecessary if it is all ones
+   or zeros and the top bit of the next lower word matches.
+
+   This function may change the representation of THIS, but does not
+   change the value that THIS represents.  It does not sign extend in
+   the case that the size of the mode is less than
+   HOST_BITS_PER_WIDE_INT.  */
+
+void
+wide_int::canonize ()
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT top;
+  int i;
+
+  if (len > blocks_needed)
+    len = blocks_needed;
+
+  /* Clean up the top bits for any mode that is not a multiple of a HWI.  */
+  if (len == blocks_needed && small_prec)
+    val[len - 1] = sext_hwi (val[len - 1], small_prec);
+
+  if (len == 1)
+    return;
+
+  top = val[len - 1];
+  if (top != 0 && top != (HOST_WIDE_INT)-1)
+    return;
+
+  /* At this point we know that the top is either 0 or -1.  Find the
+     first block that is not a copy of this.  */
+  for (i = len - 2; i >= 0; i--)
+    {
+      HOST_WIDE_INT x = val[i];
+      if (x != top)
+	{
+	  if (x >> (HOST_BITS_PER_WIDE_INT - 1) == top)
+	    {
+	      len = i + 1;
+	      return;
+	    }
+
+	  /* We need an extra block because the top bit block i does
+	     not match the extension.  */
+	  len = i + 2;
+	  return;
+	}
+    }
+
+  /* The number is 0 or -1.  */
+  len = 1;
+}
+
+
+/* Make a copy of this.  */
+
+wide_int
+wide_int::copy () const
+{
+  wide_int result;
+  int i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+  return result;
+}
+
+
+/* Copy THIS replacing the bitsize with BS and precision with PREC.
+   It can do any of truncation, extension or copying.  */
+
+wide_int
+wide_int::force_to_size (unsigned int bs, unsigned int prec, SignOp sgn) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (prec);
+  int i;
+
+  result.bitsize = bs;
+  result.precision = prec;
+  result.len = blocks_needed < len ? blocks_needed : len;
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+
+  if (prec >= precision) 
+    {
+      /* Expanding */
+      int small_precision = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+      if (sgn == UNSIGNED)
+	{
+	  if (len == BLOCKS_NEEDED (precision)
+	      && len < blocks_needed
+	      && small_precision == 0
+	      && result.val[result.len - 1] < 0)
+	    /* We need to put the 0 block on top to keep the value
+	       from being sign extended.  */ 
+	    result.val[result.len++] = 0;
+	  /* We are unsigned and the current precision is not on an
+	     even block and that block is explicitly represented.
+	     Then we have to do an explicit zext of the top block. */
+	  else if (small_precision && blocks_needed == len)
+	    result.val[blocks_needed-1]
+	      = zext_hwi (result.val[blocks_needed-1], small_precision);
+	}
+    }
+  else
+    {
+      /* Truncating.  */
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      /* The only weird case we need to look at here is when we are
+         truncating within the top block.  We need to make sure that
+         everything in the block above the new precision is sign
+         extended.  Note that this is independent of the SGN.  This is
+         just to stay canonical.  */
+      if (small_prec && (blocks_needed == len))
+	result.val[blocks_needed-1]
+	  = sext_hwi (result.val[blocks_needed-1], small_prec);
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwvvs ("wide_int:: %s = force_to_size (%s, bs = %d, prec = %d %s)\n", 
+		 result, *this, bs, prec, sgn==UNSIGNED ? "U" : "S");
+#endif
+
+  return result;
+}
+
+/*
+ * public printing routines.
+ */
+
+/* Try to print the signed self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_DEC, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decs (buf);
+  fputs (buf, file);
+}
+
+/* Try to print the unsigned self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decu (buf);
+  fputs (buf, file);
+}
+
+void 
+wide_int::print_hex (char *buf) const
+{
+  int i = len;
+
+  if (zero_p ())
+    sprintf (buf, "0x");
+  else
+    {
+      if (neg_p ())
+	{
+	  int j;
+	  /* If the number is negative, we may need to pad value with
+	     0xFFF...  because the leading elements may be missing and
+	     we do not print a '-' with hex.  */
+	  for (j = BLOCKS_NEEDED (precision); j > i; j--)
+	    buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, (HOST_WIDE_INT) -1);
+	    
+	}
+      else
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_HEX, val [--i]);
+      while (-- i >= 0)
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, val [i]);
+    }
+}
+
+/* Print one big hex number to FILE.  Note that some assemblers may not
+   accept this for large modes.  */
+void 
+wide_int::print_hex (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_hex (buf);
+  fputs (buf, file);
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently singed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+bool
+wide_int::eq_p_large (const wide_int &op1) const
+{
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  while (l0 > l1)
+    if (val[l0--] != op1.sign_mask ())
+      return false;
+
+  while (l1 > l0)
+    if (op1.val[l1--] != sign_mask ())
+      return false;
+
+  while (l0 >= 0)
+    if (val[l0--] != op1.val[l1--])
+      return false;
+
+  return true;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p_large (const wide_int &op1) const
+{
+  int l;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  int blocks_needed = BLOCKS_NEEDED (precision);
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == len ? val [blocks_needed - 1] : sign_mask ();
+  s1 = blocks_needed == op1.len ? op1.val [blocks_needed - 1] : op1.sign_mask ();
+  if (s0 < s1)
+    return true;
+  if (s0 > s1)
+    return false;
+
+  l = MAX (len, op1.len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < len ? val [l] : sign_mask ();
+      u1 = l < op1.len ? op1.val [l] : op1.sign_mask ();
+
+      if (u0 < u1)
+	return true;
+      if (u0 > u1)
+	return false;
+      l--;
+    }
+
+  return false;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+int
+wide_int::cmps_large (const wide_int &op1) const
+{
+  int l;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  int blocks_needed = BLOCKS_NEEDED (precision);
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == len ? val [blocks_needed - 1] : sign_mask ();
+  s1 = blocks_needed == op1.len ? op1.val [blocks_needed - 1] : op1.sign_mask ();
+  if (s0 < s1)
+    return -1;
+  if (s0 > s1)
+    return 1;
+
+  l = MAX (len, op1.len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < len ? val [l] : sign_mask ();
+      u1 = l < op1.len ? op1.val [l] : op1.sign_mask ();
+
+      if (u0 < u1)
+	return -1;
+      if (u0 > u1)
+	return 1;
+      l--;
+    }
+
+  return 0;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p_large (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1.sign_mask ();
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  while (l1 > l0)
+    {
+      x0 = sign_mask ();
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  return false;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+int
+wide_int::cmpu_large (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1.sign_mask ();
+      if (x0 < x1)
+	return -1;
+      else if (x0 > x1)
+	return 1;
+    }
+
+  while (l1 > l0)
+    {
+      x0 = sign_mask ();
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	return -1;
+      if (x0 > x1)
+	return 1;
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	return -1;
+      if (x0 > x1)
+	return 1;
+    }
+
+  return 0;
+}
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p (unsigned int prec) const
+{
+  int i;
+  HOST_WIDE_INT x;
+  int small_prec;
+  bool result;
+
+  if (BLOCKS_NEEDED (prec) != len)
+    {
+      result = false;
+      goto ex;
+    }
+
+  for (i=0; i < len - 1; i++)
+    if (val[i] != 0)
+      {
+	result = false;
+	goto ex;
+      }
+
+  x = val[len - 1];
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec)
+    x = x << (HOST_BITS_PER_WIDE_INT - small_prec);
+
+  result = x == ((HOST_WIDE_INT)1) << (HOST_BITS_PER_WIDE_INT - 1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = only_sign_bit_p (%s)\n", result, *this);
+#endif
+
+  return result;
+}
+
+/* Returns true if THIS fits into range of TYPE.  Signedness of OP0 is
+   assumed to be the same as the signedness of TYPE.  */
+
+bool
+wide_int::fits_to_tree_p (const_tree type) const
+{
+  int type_prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return fits_u_p (type_prec);
+  else
+    return fits_s_p (type_prec);
+}
+
+/* Returns true of THIS fits in the unsigned range of precision.  */
+
+bool
+wide_int::fits_s_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == sext (prec);
+}
+
+
+/* Returns true if THIS fits into range of TYPE.  */
+
+bool
+wide_int::fits_u_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == zext (prec);
+}
+
+/*
+ * Extension.
+ */
+
+/* Sign extend THIS starting at OFFSET.  The bitsize and precision of
+   the result are the same as THIS.  */
+
+wide_int
+wide_int::sext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.bitsize = bitsize;
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = sext_hwi (val[0], offset);
+      else
+	/* If offset is greater or equal to precision there is nothing
+	   to do since the internal rep is already sign extended.  */
+	result.val[0] = val[0];
+
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, bitsize, precision);
+      
+      /* Now we can do the real sign extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      if (off)
+	{
+	  int block = BLOCK_OF (offset);
+	  result.val[block] = sext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      /* We never need an extra element for sign extended values.  */
+    }    
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s sext %d)\n", result, *this, offset);
+#endif
+
+  return result;
+}
+
+/* Zero extend THIS starting at OFFSET.  The bitsize and precision of
+   the result are the same as THIS.  */
+
+wide_int
+wide_int::zext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+  int block;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.bitsize = bitsize;
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = zext_hwi (val[0], offset);
+      else if (offset == precision)
+	result.val[0] = val[0];
+	/* If offset was greater than the precision we need to zero
+	   extend from the old precision since the internal rep was
+	   equivalent to sign extended.  */
+      else
+	result.val[0] = zext_hwi (val[0], precision);
+	
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, bitsize, precision);
+
+      /* Now we can do the real zero extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      block = BLOCK_OF (offset);
+      if (off)
+	{
+	  result.val[block] = zext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      else
+	/* See if we need an extra zero element to satisfy the
+	   compression rule.  */
+	if (val[block - 1] < 0 && offset < precision)
+	  {
+	    result.val[block] = 0;
+	    result.len += 1;
+	  }
+    }
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s zext %d)\n", result, *this, offset);
+#endif
+
+  return result;
+}
+
+/*
+ * Masking, inserting, shifting, rotating.
+ */
+
+/* Return a value with a one bit inserted in THIS at BITPOS.  */
+
+wide_int
+wide_int::set_bit (unsigned int bitpos) const
+{
+  wide_int result;
+  int i, j;
+
+  if (bitpos >= precision)
+    result = copy ();
+  else
+    {
+      result = decompress (bitpos, bitsize, precision);
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s set_bit %d)\n", result, *this, bitpos);
+#endif
+
+  return result;
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with BITSIZE
+   and PRECISION.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, 
+			   unsigned int bitsize, unsigned int prec)
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (bitpos + 1);
+  int i, j;
+
+  result.bitsize = bitsize;
+  result.precision = prec;
+  if (bitpos >= prec)
+    {
+      result.len = 1;
+      result.val[0] = 0;
+    }
+  else
+    {
+      result.len = blocks_needed;
+      for (i = 0; i < blocks_needed; i++)
+	result.val[i] = 0;
+      
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wv ("wide_int:: %s = set_bit_in_zero (%d)\n", result, bitpos);
+#endif
+
+  return result;
+}
+
+/* Insert WIDTH bits from OP0 into THIS starting at START.  */
+
+wide_int
+wide_int::insert (const wide_int &op0, unsigned int start, 
+		  unsigned int width) const
+{
+  wide_int result;
+  wide_int mask;
+  wide_int tmp;
+
+  if (start + width >= precision) 
+    width = precision - start;
+
+  mask = shifted_mask (start, width, false, bitsize, precision);
+  tmp = op0.lshift (start, NONE, bitsize, precision);
+  result = tmp & mask;
+
+  tmp = and_not (mask);
+  result = result | tmp;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwwvv ("wide_int:: %s = (%s insert start = %d width = %d)\n", 
+		 result, *this, op0, start, width);
+#endif
+
+  return result;
+}
+
+/* bswap THIS.  */
+
+wide_int
+wide_int::bswap () const
+{
+  wide_int result;
+  int i, s;
+  int end;
+  int len = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT mask = sign_mask ();
+
+  /* This is not a well defined operation if the precision is not a
+     multiple of 8.  */
+  gcc_assert ((precision & 0x7) == 0);
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < len; i++)
+    result.val[0] = mask;
+
+  /* Only swap the bytes that are not the padding.  */
+  if ((precision & (HOST_BITS_PER_WIDE_INT - 1))
+      && (this->len == len))
+    end = precision;
+  else
+    end = this->len * HOST_BITS_PER_WIDE_INT;
+
+  for (s = 0; s < end; s += 8)
+    {
+      unsigned int d = precision - s - 8;
+      unsigned HOST_WIDE_INT byte;
+
+      int block = s / HOST_BITS_PER_WIDE_INT;
+      int offset = s & (HOST_BITS_PER_WIDE_INT - 1);
+
+      byte = (val[block] >> offset) & 0xff;
+
+      block = d / HOST_BITS_PER_WIDE_INT;
+      offset = d & (HOST_BITS_PER_WIDE_INT - 1);
+
+      result.val[block] &= ((((HOST_WIDE_INT)1 << offset) + 8)
+			    - ((HOST_WIDE_INT)1 << offset));
+      result.val[block] |= byte << offset;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = bswap (%s)\n", result, *this);
+#endif
+
+  return result;
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with BITSIZE and
+   PREC. */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, 
+		unsigned int bitsize, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  int shift;
+
+  gcc_assert (width < 2 * MAX_BITSIZE_MODE_ANY_INT);
+  gcc_assert (prec <= 2 * MAX_BITSIZE_MODE_ANY_INT);
+
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (bitsize, prec);
+      else
+	result = wide_int::zero (bitsize, prec);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wvv ("wide_int:: %s = mask (%d, negate = %d)\n", result, width, negate);
+#endif
+      return result;
+    }
+
+  result.bitsize = bitsize;
+  result.precision = prec;
+
+  while (i < width / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = width & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      HOST_WIDE_INT last = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~last : last;
+    }
+  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvv ("wide_int:: %s = mask (%d, negate = %d)\n", result, width, negate);
+#endif
+
+  return result;
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  */
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate,
+			unsigned int bitsize, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  unsigned int shift;
+  unsigned int end = start + width;
+  HOST_WIDE_INT block;
+
+  if (start + width > prec)
+    width = prec - start;
+ 
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (bitsize, prec);
+      else
+	result = wide_int::zero (bitsize, prec);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wvvv 
+	  ("wide_int:: %s = shifted_mask (start = %d width = %d negate = %d)\n", 
+	   result, start, width, negate);
+#endif
+      return result;
+    }
+
+  result.bitsize = bitsize;
+  result.precision = prec;
+
+  while (i < start / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? (HOST_WIDE_INT)-1 : 0;
+
+  shift = start & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift)
+    {
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      shift = (end) & (HOST_BITS_PER_WIDE_INT - 1);
+      if (shift)
+	{
+	  /* case 000111000 */
+	  block = (((HOST_WIDE_INT)1) << shift) - block - 1;
+	  result.val[i++] = negate ? ~block : block;
+	  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_wvvv 
+	      ("wide_int:: %s = shifted_mask (start = %d width = %d negate = %d)\n", 
+	       result, start, width, negate);
+#endif
+	  return result;
+	}
+      else
+	/* ...111000 */
+	result.val[i++] = negate ? block : ~block;
+    }
+
+  while (i < end / HOST_BITS_PER_WIDE_INT)
+    /* 1111111 */
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = end & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      /* 000011111 */
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~block : block;
+    }
+
+  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvvv 
+      ("wide_int:: %s = shifted_mask (start = %d width = %d negate = %d)\n", 
+       result, start, width, negate);
+#endif
+
+  return result;
+}
+
+
+/*
+ * logical operations.
+ */
+
+/* Return THIS & OP1.  */
+
+wide_int
+wide_int::and_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Return THIS & ~OP1.  */
+
+wide_int
+wide_int::and_not_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & ~op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+wide_int
+wide_int::or_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+  return result;
+}
+
+/* Return THIS | ~OP1.  */
+
+wide_int
+wide_int::or_not_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | ~op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Return the exclusive ior (xor) of THIS and OP1.  */
+
+wide_int
+wide_int::xor_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  while (l0 > l1)
+    {
+      result.val[l0] = val[l0] ^ op1.sign_mask ();
+      l0--;
+    }
+
+  while (l1 > l0)
+    {
+      result.val[l1] = sign_mask () ^ op1.val[l1];
+      l1--;
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] ^ op1.val[l0];
+      l0--;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s ^ %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/*
+ * math
+ */
+
+/* Absolute value of THIS.  */
+
+wide_int
+wide_int::abs () const
+{
+  if (sign_mask ())
+    return neg ();
+
+  wide_int result = copy ();
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = abs (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Add of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::add_large (const wide_int &op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1.len ? (unsigned HOST_WIDE_INT)op1.val[i] : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 + mask1 + carry;
+      result.len++;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/* Add of OP0 and OP1 with overflow checking.  If the result overflows
+   within the precision, set OVERFLOW.  OVERFLOW is assumed to be
+   sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::add (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT old_carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int i, small_prec;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < len; i++)
+    {
+      o0 = val[i];
+      o1 = op1.val[i];
+      x = o0 + o1 + carry;
+      result.val [i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+
+  /* Uncompress the rest.  */
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = val[i];
+      o1 = mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = mask0;
+      o1 = op1.val[i];
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 + mask1 + carry;
+      result.len++;
+      /* If we were short, we could not have overflowed.  */
+      goto ex;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (sgn == wide_int::SIGNED)
+	{
+	  if (((!(o0 ^ o1)) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
+	    *overflow = true;
+	}
+      else if (old_carry)
+	{
+	  if ((~o0) <= o1)
+	    *overflow = true;
+	}
+      else
+	{
+	  if ((~o0) < o1)
+	    *overflow = true;
+	}
+    }
+  else
+    {
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  If there are any non zero bits above the prec,
+	     we overflowed. */
+	  o0 = zext_hwi (o0, small_prec);
+	  o1 = zext_hwi (o1, small_prec);
+	  x = o0 + o1 + old_carry;
+	  if (x >> small_prec)
+	    *overflow = true;
+	}
+      else 
+	{
+	  /* Overflow in this case is easy since we can see bits beyond
+	     the precision.  If the value computed is not the sign
+	     extended value, then we have overflow.  */
+	  unsigned HOST_WIDE_INT y = sext_hwi (x, small_prec);
+	  if (x != y)
+	    *overflow = true;
+	}
+    }
+
+ ex:
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvww ("wide_int:: %s %d = (%s +O %s)\n", 
+	       result, *overflow, *this, op1);
+#endif
+  return result;
+}
+
+/* Count leading zeros of THIS but only looking at the bits in the
+   smallest HWI of size mode.  */
+
+wide_int
+wide_int::clz (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (clz (), bs, prec);
+}
+
+/* Count leading zeros of THIS.  */
+
+int
+wide_int::clz () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_vw ("wide_int:: %d = clz (%s)\n", count, *this);
+#endif
+      return count;
+    }
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = clz_hwi (v) - (HOST_BITS_PER_WIDE_INT - small_prec);
+      start = len - 2;
+      if (v != 0)
+	{
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_vw ("wide_int:: %d = clz (%s)\n", count, *this);
+#endif
+	  return count;
+	}
+    }
+  else
+    {
+      count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = elt (i);
+      count += clz_hwi (v);
+      if (v != 0)
+	break;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = clz (%s)\n", count, *this);
+#endif
+  return count;
+}
+
+wide_int
+wide_int::clrsb (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (clrsb (), bs, prec);
+}
+
+/* Count the number of redundant leading bits of THIS.  Return result
+   as a HOST_WIDE_INT.  There is a wrapper to convert this into a
+   wide_int.  */
+
+int
+wide_int::clrsb () const
+{
+  if (neg_p ())
+    return operator ~ ().clz () - 1;
+
+  return clz () - 1;
+}
+
+wide_int
+wide_int::ctz (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (ctz (), bs, prec);
+}
+
+/* Count zeros of THIS.  Return result as a HOST_WIDE_INT.  There is a
+   wrapper to convert this into a wide_int.  */
+
+int
+wide_int::ctz () const
+{
+  int i;
+  unsigned int count = 0;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int end;
+  bool more_to_do;
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_vw ("wide_int:: %d = ctz (%s)\n", count, *this);
+#endif
+      return count;
+    }
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      end = len - 1;
+      more_to_do = true;
+    }
+  else
+    {
+      end = len;
+      more_to_do = false;
+    }
+
+  for (i = 0; i < end; i++)
+    {
+      v = val[i];
+      count += ctz_hwi (v);
+      if (v != 0)
+	{
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_vw ("wide_int:: %d = ctz (%s)\n", count, *this);
+#endif
+	  return count;
+	}
+    }
+
+  if (more_to_do)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = ctz_hwi (v);
+      /* The top word was all zeros so we have to cut it back to prec,
+	 because we are counting some of the zeros above the
+	 interesting part.  */
+      if (count > precision)
+	count = precision;
+    }
+  else
+    /* Skip over the blocks that are not represented.  They must be
+       all zeros at this point.  */
+    count = precision;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = ctz (%s)\n", count, *this);
+#endif
+  return count;
+}
+
+/* ffs of THIS.  */
+
+wide_int
+wide_int::ffs () const
+{
+  HOST_WIDE_INT count = ctz ();
+  if (count == precision)
+    count = 0;
+  else
+    count += 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = ffs (%s)\n", count, *this);
+#endif
+  return wide_int::from_shwi (count, word_mode);
+}
+
+/* Subroutines of the multiplication and division operations.  Unpack
+   the first IN_LEN HOST_WIDE_INTs in INPUT into 2 * IN_LEN
+   HOST_HALF_WIDE_INTs of RESULT.  The rest of RESULT is filled by
+   uncompressing the top bit of INPUT[IN_LEN - 1].  */
+
+static void
+wi_unpack (unsigned HOST_HALF_WIDE_INT *result, 
+	   const unsigned HOST_WIDE_INT *input,
+	   int in_len, int out_len)
+{
+  int i;
+  int j = 0;
+  HOST_WIDE_INT mask;
+
+  for (i = 0; i <in_len; i++)
+    {
+      result[j++] = input[i];
+      result[j++] = input[i] >> HOST_BITS_PER_HALF_WIDE_INT;
+    }
+  mask = ((HOST_WIDE_INT)input[in_len - 1]) >> (HOST_BITS_PER_WIDE_INT - 1);
+  mask &= HALF_INT_MASK;
+
+  /* Smear the sign bit.  */
+  while (j < out_len)
+    result[j++] = mask;
+}
+
+/* The inverse of wi_unpack.  IN_LEN is the the number of input
+   blocks.  The number of output blocks will be half this amount.  */
+
+static void
+wi_pack (unsigned HOST_WIDE_INT *result, 
+	 const unsigned HOST_HALF_WIDE_INT *input, 
+	 int in_len)
+{
+  int i = 0;
+  int j = 0;
+
+  while (i < in_len - 2)
+    {
+      result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+	| ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+      i += 2;
+    }
+
+  /* Handle the case where in_len is odd.   For this we zero extend.  */
+  if (i & 1)
+    result[j++] = (unsigned HOST_WIDE_INT)input[i];
+  else
+    result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+      | ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+}
+
+/* Return an integer that is the exact log2 of THIS.  */
+
+int
+wide_int::exact_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  HOST_WIDE_INT count;
+  HOST_WIDE_INT result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec)
+	v = zext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = ::exact_log2 (v);
+      goto ex;
+    }
+
+  count = ctz ();
+  if (clz () + count + 1 == precision)
+    {
+      result = count;
+      goto ex;
+    }
+
+  result = -1;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = exact_log2 (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Return an integer that is the floor log2 of THIS.  */
+
+int
+wide_int::floor_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  HOST_WIDE_INT result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec)
+	v = zext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = ::floor_log2 (v);
+      goto ex;
+    }
+
+  result = precision - 1 - clz ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = floor_log2 (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+
+/* Multiply Op1 by Op2.  If HIGH is set, only the upper half of the
+   result is returned.  If FULL is set, the entire result is returned
+   in a mode that is twice the width of the inputs.  However, that
+   mode needs to exist if the value is to be usable.  Clients that use
+   FULL need to check for this.
+
+   If HIGH or FULL are not setm throw away the upper half after the check
+   is made to see if it overflows.  Unfortunately there is no better
+   way to check for overflow than to do this.  OVERFLOW is assumed to
+   be sticky so it should be initialized.  SGN controls the signess
+   and is used to check overflow or if HIGH or FULL is set.  */
+
+wide_int
+wide_int::mul_internal (bool high, bool full, 
+			const wide_int *op1, const wide_int *op2,
+			wide_int::SignOp sgn,  bool *overflow, 
+			bool needs_overflow)
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1, k, t;
+  unsigned int i;
+  unsigned int j;
+  unsigned int prec = op1->get_precision ();
+  unsigned int blocks_needed = BLOCKS_NEEDED (prec);
+  unsigned int half_blocks_needed = blocks_needed * 2;
+  /* The sizes here are scaled to support a 2x largest mode by 2x
+     largest mode yielding a 4x largest mode result.  This is what is
+     needed by vpn.  */
+
+  unsigned HOST_HALF_WIDE_INT 
+    u[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT 
+    v[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  /* The '2' in 'R' is because we are internally doing a full
+     multiply.  */
+  unsigned HOST_HALF_WIDE_INT 
+    r[2 * 2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1;
+
+  result.bitsize = op1->bitsize;
+  result.precision = op1->precision;
+
+  if (high || full || needs_overflow)
+    {
+      /* If we need to check for overflow, we can only do half wide
+	 multiplies quickly because we need to look at the top bits to
+	 check for the overflow.  */
+      if (prec <= HOST_BITS_PER_HALF_WIDE_INT)
+	{
+	  HOST_WIDE_INT t, r;
+	  result.len = 1;
+	  o0 = op1->elt (0);
+	  o1 = op2->elt (0);
+	  r = o0 * o1;
+	  /* Signed shift down will leave 0 or -1 if there was no
+	     overflow for signed or 0 for unsigned.  */
+	  t = r >> (HOST_BITS_PER_HALF_WIDE_INT - 1);
+	  if (needs_overflow)
+	    {
+	      if (sgn == wide_int::SIGNED)
+		{
+		  if (t != (HOST_WIDE_INT)-1 && t != 0)
+		    *overflow = true;
+		}
+	      else
+		{
+		  if (t != 0)
+		    *overflow = true;
+		}
+	    }
+	  if (full)
+	    {
+	      result.val[0] = sext_hwi (r, prec * 2);
+	      result.bitsize = op1->bitsize * 2;
+	      result.precision = op1->precision * 2;
+	    }
+	  else if (high)
+	    result.val[0] = r >> prec;
+	  else
+	    result.val[0] = sext_hwi (r, prec);
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_wvww ("wide_int:: %s %d = (%s *O %s)\n", 
+			result, *overflow, *op1, *op2);
+#endif
+	  return result;
+	}
+    }
+
+  wi_unpack (u, (const unsigned HOST_WIDE_INT*)op1->val, op1->len,
+	     half_blocks_needed);
+  wi_unpack (v, (const unsigned HOST_WIDE_INT*)op2->val, op2->len,
+	     half_blocks_needed);
+
+  /* The 2 is for a full mult.  */
+  memset (r, 0, half_blocks_needed * 2 
+	  * HOST_BITS_PER_HALF_WIDE_INT / BITS_PER_UNIT);
+
+  for (j = 0; j < half_blocks_needed; j++)
+    {
+      k = 0;
+      for (i = 0; i < half_blocks_needed; i++)
+	{
+	  t = ((unsigned HOST_WIDE_INT)u[i] * (unsigned HOST_WIDE_INT)v[j]
+	       + r[i + j] + k);
+	  r[i + j] = t & HALF_INT_MASK;
+	  k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	}
+      r[j + half_blocks_needed] = k;
+    }
+
+  /* We did unsigned math above.  For signed we must adjust the
+     product (assuming we need to see that).  */
+  if (sgn == wide_int::SIGNED && (full || high || needs_overflow))
+    {
+      unsigned HOST_WIDE_INT b;
+      if ((*op1).neg_p ())
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)v[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+      if ((*op2).neg_p ())
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)u[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+    }
+
+  if (needs_overflow)
+    {
+      HOST_WIDE_INT top;
+
+      /* For unsigned, overflow is true if any of the top bits are set.
+	 For signed, overflow is true if any of the top bits are not equal
+	 to the sign bit.  */
+      if (sgn == wide_int::UNSIGNED)
+	top = 0;
+      else
+	{
+	  top = r[(half_blocks_needed) - 1];
+	  top = ((top << (HOST_BITS_PER_WIDE_INT / 2))
+		 >> (HOST_BITS_PER_WIDE_INT - 1));
+	  top &= mask;
+	}
+      
+      for (i = half_blocks_needed; i < half_blocks_needed * 2; i++)
+	if (((HOST_WIDE_INT)(r[i] & mask)) != top)
+	  *overflow = true; 
+    }
+
+  if (full)
+    {
+      /* compute [2prec] <- [prec] * [prec] */
+      wi_pack ((unsigned HOST_WIDE_INT*)result.val, r, 2 * half_blocks_needed);
+      result.len = blocks_needed * 2;
+      result.bitsize = op1->bitsize * 2;
+      result.precision = op1->precision * 2;
+    }
+  else if (high)
+    {
+      /* compute [prec] <- ([prec] * [prec]) >> [prec] */
+      wi_pack ((unsigned HOST_WIDE_INT*)&result.val [blocks_needed >> 1],
+	       r, half_blocks_needed);
+      result.len = blocks_needed;
+    }
+  else
+    {
+      /* compute [prec] <- ([prec] * [prec]) && ((1 << [prec]) - 1) */
+      wi_pack ((unsigned HOST_WIDE_INT*)result.val, r, half_blocks_needed);
+      result.len = blocks_needed;
+    }
+      
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvww ("wide_int:: %s %d = (%s *O %s)\n", 
+		result, *overflow, *op1, *op2);
+#endif
+  return result;
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.
+   OVERFLOW is set true if the result overflows.  */
+
+wide_int 
+wide_int::mul (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  return mul_internal (false, false, this, &op1, sgn, overflow, true);
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.  The
+   result is twice the precision as the operands.  The signess is
+   specified with SGN.  */
+
+wide_int
+wide_int::mul_full (const wide_int &op1, SignOp sgn) const
+{
+  bool overflow = false;
+
+  return mul_internal (false, true, this, &op1, sgn, &overflow, false);
+}
+
+/* Multiply THIS and OP1 and return the high part of that result.  The
+   signess is specified with SGN.  The result is the same precision as
+   the operands.  The mode is the same mode as the operands.  The
+   signess is specified with y.  */
+
+wide_int
+wide_int::mul_high (const wide_int &op1, SignOp sgn) const
+{
+  bool overflow = false;
+
+  return mul_internal (true, false, this, &op1, sgn, &overflow, false);
+}
+
+/* Compute the parity of THIS.  */
+
+wide_int
+wide_int::parity (unsigned int bs, unsigned int prec) const
+{
+  int count = popcount ();
+  return wide_int::from_shwi (count & 1, bs, prec);
+}
+
+/* Compute the population count of THIS producing a number with
+   BITSIZE and PREC.  */
+
+wide_int
+wide_int::popcount (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (popcount (), bs, prec);
+}
+
+/* Compute the population count of THIS.  */
+
+int
+wide_int::popcount () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = popcount_hwi (v);
+      start = len - 2;
+    }
+  else
+    {
+      if (sign_mask ())
+	count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      else
+	count = 0;
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = val[i];
+      count += popcount_hwi (v);
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = popcount (%s)\n", count, *this);
+#endif
+  return count;
+}
+
+/* Subtract of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::sub_large (const wide_int &op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the borrow in of the first element at 1.  */
+  unsigned HOST_WIDE_INT borrow = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1.len ? (unsigned HOST_WIDE_INT)op1.val[i] : mask1;
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      borrow = o0 < o1;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 - mask1 - borrow;
+      result.len++;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/* Subtract of THIS and OP1 with overflow checking.  If the result
+   overflows within the precision, set OVERFLOW.  OVERFLOW is assumed
+   to be sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::sub (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT borrow = 0;
+  unsigned HOST_WIDE_INT old_borrow = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int i, small_prec;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < len; i++)
+    {
+      o0 = val[i];
+      o1 = op1.val[i];
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  /* Uncompress the rest.  */
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = val[i];
+      o1 = mask1;
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  for (i = op1.len; i < len; i++)
+    {
+      o0 = mask0;
+      o1 = op1.val[i];
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 - mask1 - borrow;
+      result.len++;
+      /* If we were short, we could not have overflowed.  */
+      goto ex;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (sgn == wide_int::SIGNED)
+	{
+	  if (((x ^ o0) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
+	    *overflow = true;
+	}
+      else if (old_borrow)
+	{
+	  if ((~o0) <= o1)
+	    *overflow = true;
+	}
+      else
+	{
+	  if ((~o0) < o1)
+	    *overflow = true;
+	}
+    }
+  else
+    {
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  If there are any non zero bits above the prec,
+	     we overflowed. */
+	  o0 = zext_hwi (o0, small_prec);
+	  o1 = zext_hwi (o1, small_prec);
+	  x = o0 - o1 - old_borrow;
+	  if (x >> small_prec)
+	    *overflow = true;
+	}
+      else 
+	{
+	  /* Overflow in this case is easy since we can see bits beyond
+	     the precision.  If the value computed is not the sign
+	     extended value, then we have overflow.  */
+	  unsigned HOST_WIDE_INT y = sext_hwi (x, small_prec);
+	  if (x != y)
+	    *overflow = true;
+	}
+    }
+
+ ex:
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvww ("wide_int:: %s %d = (%s -O %s)\n", 
+		result, *overflow, *this, op1);
+#endif
+  return result;
+}
+
+/*
+ * Division and Mod
+ */
+
+/* Compute B_QUOTIENT and B_REMAINDER from B_DIVIDEND/B_DIVISOR.  The
+   algorithm is a small modification of the algorithm in Hacker's
+   Delight by Warren, which itself is a small modification of Knuth's
+   algorithm.  M is the number of significant elements of U however
+   there needs to be at least one extra element of B_DIVIDEND
+   allocated, N is the number of elements of B_DIVISOR.  */
+
+void
+wide_int::divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+			     unsigned HOST_HALF_WIDE_INT *b_remainder,
+			     unsigned HOST_HALF_WIDE_INT *b_dividend, 
+			     unsigned HOST_HALF_WIDE_INT *b_divisor, 
+			     int m, int n)
+{
+  /* The "digits" are a HOST_HALF_WIDE_INT which the size of half of a
+     HOST_WIDE_INT and stored in the lower bits of each word.  This
+     algorithm should work properly on both 32 and 64 bit
+     machines.  */
+  unsigned HOST_WIDE_INT b
+    = (unsigned HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT;
+  unsigned HOST_WIDE_INT qhat;   /* Estimate of quotient digit.  */
+  unsigned HOST_WIDE_INT rhat;   /* A remainder.  */
+  unsigned HOST_WIDE_INT p;      /* Product of two digits.  */
+  HOST_WIDE_INT s, i, j, t, k;
+
+  /* Single digit divisor.  */
+  if (n == 1)
+    {
+      k = 0;
+      for (j = m - 1; j >= 0; j--)
+	{
+	  b_quotient[j] = (k * b + b_dividend[j])/b_divisor[0];
+	  k = ((k * b + b_dividend[j])
+	       - ((unsigned HOST_WIDE_INT)b_quotient[j]
+		  * (unsigned HOST_WIDE_INT)b_divisor[0]));
+	}
+      b_remainder[0] = k;
+      return;
+    }
+
+  s = clz_hwi (b_divisor[n-1]) - HOST_BITS_PER_HALF_WIDE_INT; /* CHECK clz */
+
+  /* Normalize B_DIVIDEND and B_DIVISOR.  Unlike the published
+     algorithm, we can overwrite b_dividend and b_divisor, so we do
+     that.  */
+  for (i = n - 1; i > 0; i--)
+    b_divisor[i] = (b_divisor[i] << s)
+      | (b_divisor[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_divisor[0] = b_divisor[0] << s;
+
+  b_dividend[m] = b_dividend[m-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s);
+  for (i = m - 1; i > 0; i--)
+    b_dividend[i] = (b_dividend[i] << s)
+      | (b_dividend[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_dividend[0] = b_dividend[0] << s;
+
+  /* Main loop.  */
+  for (j = m - n; j >= 0; j--)
+    {
+      qhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) / b_divisor[n-1];
+      rhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) - qhat * b_divisor[n-1];
+    again:
+      if (qhat >= b || qhat * b_divisor[n-2] > b * rhat + b_dividend[j+n-2])
+	{
+	  qhat -= 1;
+	  rhat += b_divisor[n-1];
+	  if (rhat < b)
+	    goto again;
+	}
+
+      /* Multiply and subtract.  */
+      k = 0;
+      for (i = 0; i < n; i++)
+	{
+	  p = qhat * b_divisor[i];
+	  t = b_dividend[i+j] - k - (p & HALF_INT_MASK);
+	  b_dividend[i + j] = t;
+	  k = ((p >> HOST_BITS_PER_HALF_WIDE_INT)
+	       - (t >> HOST_BITS_PER_HALF_WIDE_INT));
+	}
+      t = b_dividend[j+n] - k;
+      b_dividend[j+n] = t;
+
+      b_quotient[j] = qhat;
+      if (t < 0)
+	{
+	  b_quotient[j] -= 1;
+	  k = 0;
+	  for (i = 0; i < n; i++)
+	    {
+	      t = (HOST_WIDE_INT)b_dividend[i+j] + b_divisor[i] + k;
+	      b_dividend[i+j] = t;
+	      k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	    }
+	  b_dividend[j+n] += k;
+	}
+    }
+  for (i = 0; i < n; i++)
+    b_remainder[i] = (b_dividend[i] >> s) 
+      | (b_dividend[i+1] << (HOST_BITS_PER_HALF_WIDE_INT - s));
+}
+
+
+/* Do a truncating divide DIVISOR into DIVIDEND.  The result is the
+   same size as the operands.  SIGN is either wide_int::SIGNED or
+   wide_int::UNSIGNED.  */
+
+wide_int
+wide_int::divmod_internal (bool compute_quotient, 
+			   const wide_int *dividend, const wide_int *divisor,
+			   wide_int::SignOp sgn, wide_int *remainder,
+			   bool compute_remainder, 
+			   bool *overflow)
+{
+  wide_int quotient, u0, u1;
+  unsigned int prec = dividend->get_precision();
+  unsigned int bs = dividend->get_bitsize ();
+  int blocks_needed = 2 * BLOCKS_NEEDED (prec);
+  /* The '2' in the next 4 vars are because they are built on half
+     sized wide ints.  */
+  unsigned HOST_HALF_WIDE_INT 
+    b_quotient[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_remainder[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_dividend[(MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT) + 1];
+  unsigned HOST_HALF_WIDE_INT
+    b_divisor[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  int m, n;
+  bool dividend_neg = false;
+  bool divisor_neg = false;
+
+  if ((*divisor).zero_p ())
+    *overflow = true;
+
+  /* The smallest signed number / -1 causes overflow.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      wide_int t = wide_int::set_bit_in_zero (prec - 1, 
+					      bs, 
+					      prec);
+      if (*dividend == t && (*divisor).minus_one_p ())
+	*overflow = true;
+    }
+
+  quotient.bitsize = bs;
+  remainder->bitsize = bs;
+  quotient.precision = prec;
+  remainder->precision = prec;
+
+  /* If overflow is set, just get out.  There will only be grief by
+     continuing.  */
+  if (*overflow)
+    {
+      if (compute_remainder)
+	{
+	  remainder->len = 1;
+	  remainder->val[0] = 0;
+	}
+      return wide_int::zero (bs, prec);
+    }
+
+  /* Do it on the host if you can.  */
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      quotient.len = 1;
+      remainder->len = 1;
+      if (sgn == wide_int::SIGNED)
+	{
+	  quotient.val[0] 
+	    = sext_hwi (dividend->elt (0) / divisor->val[0], prec);
+	  remainder->val[0] 
+	    = sext_hwi (dividend->elt (0) % divisor->val[0], prec);
+	}
+      else
+	{
+	  unsigned HOST_WIDE_INT o0 = dividend->elt (0);
+	  unsigned HOST_WIDE_INT o1 = divisor->elt (0);
+
+	  if (prec < HOST_BITS_PER_WIDE_INT)
+	    {
+	      o0 = zext_hwi (o0, prec);
+	      o1 = zext_hwi (o1, prec);
+	    }
+	  quotient.val[0] = sext_hwi (o0 / o1, prec);
+	  remainder->val[0] = sext_hwi (o0 % o1, prec);
+	}
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwww ("wide_int:: (q = %s) (r = %s) = (%s / %s)\n", 
+		    quotient, *remainder, *dividend, *divisor);
+#endif
+      return quotient;
+    }
+
+  /* Make the divisor and divident positive and remember what we
+     did.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      if (dividend->sign_mask ())
+	{
+	  u0 = dividend->neg ();
+	  dividend = &u0;
+	  dividend_neg = true;
+	}
+      if (divisor->sign_mask ())
+	{
+	  u1 = divisor->neg ();
+	  divisor = &u1;
+	  divisor_neg = true;
+	}
+    }
+
+  wi_unpack (b_dividend, (const unsigned HOST_WIDE_INT*)dividend->val,
+	     dividend->len, blocks_needed);
+  wi_unpack (b_divisor, (const unsigned HOST_WIDE_INT*)divisor->val, 
+	     divisor->len, blocks_needed);
+
+  if (dividend->sign_mask ())
+    m = blocks_needed;
+  else
+    m = 2 * dividend->get_len ();
+
+  if (divisor->sign_mask ())
+    n = blocks_needed;
+  else
+    n = 2 * divisor->get_len ();
+
+  /* It is known that the top input block to the divisor is non zero,
+     but when this block is split into two half blocks, it may be that
+     the top half block is zero.  Skip over this half block.  */
+  if (b_divisor[n - 1] == 0)
+    n--;
+
+  divmod_internal_2 (b_quotient, b_remainder, b_dividend, b_divisor, m, n);
+
+  if (compute_quotient)
+    {
+      wi_pack ((unsigned HOST_WIDE_INT*)quotient.val, b_quotient, m);
+      quotient.len = m / 2;
+      quotient.canonize ();
+      /* The quotient is neg if exactly one of the divisor or dividend is
+	 neg.  */
+      if (dividend_neg != divisor_neg)
+	quotient = quotient.neg ();
+    }
+  else
+    quotient = wide_int::zero (word_mode);
+
+  if (compute_remainder)
+    {
+      wi_pack ((unsigned HOST_WIDE_INT*)remainder->val, b_remainder, n);
+      if (n & 1)
+	n++;
+      remainder->len = n / 2;
+      (*remainder).canonize ();
+      /* The remainder is always the same sign as the dividend.  */
+      if (dividend_neg)
+	*remainder = (*remainder).neg ();
+    }
+  else
+    *remainder = wide_int::zero (word_mode);
+
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwww ("wide_int:: (q = %s) (r = %s) = (%s / %s)\n", 
+		quotient, *remainder, *dividend, *divisor);
+#endif
+  return quotient;
+}
+
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is
+   truncated.  */
+
+wide_int
+wide_int::div_trunc (const wide_int &divisor, SignOp sgn) const
+{
+  wide_int remainder;
+  bool overflow = false;
+
+  return divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, false, &overflow);
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is truncated.
+   Overflow is set to true if the result overflows, otherwise it is
+   not set.  */
+wide_int
+wide_int::div_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  
+  return divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, false, overflow);
+}
+
+/* Divide DIVISOR into THIS producing both the quotient and remainder.
+   The result is the same size as the operands.  The sign is specified
+   in SGN.  The output is truncated.  */
+
+wide_int
+wide_int::divmod_trunc (const wide_int &divisor, wide_int *remainder, SignOp sgn) const
+{
+  bool overflow = false;
+
+  return divmod_internal (true, this, &divisor, sgn, 
+			  remainder, true, &overflow);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  */
+
+wide_int
+wide_int::mod_trunc (const wide_int &divisor, SignOp sgn) const
+{
+  bool overflow = false;
+  wide_int remainder;
+
+  divmod_internal (false, this, &divisor, sgn, 
+		   &remainder, true, &overflow);
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+
+  divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, true, overflow);
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is floor
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return quotient - wide_int::one (bitsize, precision);
+  return quotient;
+}
+
+
+/* Divide DIVISOR into THIS.  The remainder is also produced in
+   REMAINDER.  The result is the same size as the operands.  The sign
+   is specified in SGN.  The output is floor truncated.  Overflow is
+   set to true if the result overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::divmod_floor (const wide_int &divisor, wide_int *remainder, SignOp sgn) const
+{
+  wide_int quotient;
+  bool overflow = false;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      remainder, true, &overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !(*remainder).zero_p ())
+    {
+      *remainder = *remainder - divisor;
+      return quotient - wide_int::one (bitsize, precision);
+    }
+  return quotient;
+}
+
+
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is floor truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return remainder - divisor;
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is ceil
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return quotient;
+      else
+	return quotient + wide_int::one (bitsize, precision);
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is the
+   same size as the operands.  The sign is specified in SGN.  The
+   output is ceil truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return remainder;
+      else
+	return remainder - divisor;
+    }
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is round
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_round (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+  if (!remainder.zero_p ())
+    {
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return quotient - wide_int::one (bitsize, precision);
+	      else 
+		return quotient + wide_int::one (bitsize, precision);
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return quotient + wide_int::one (bitsize, precision);
+	}
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is round truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_round (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return remainder + divisor;
+	      else 
+		return remainder - divisor;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return remainder - divisor;
+	}
+    }
+  return remainder;
+}
+
+/*
+ * Shifting, rotating and extraction.
+ */
+
+/* Extract WIDTH bits from THIS starting at OFFSET.  The result is
+   assumed to fit in a HOST_WIDE_INT.  This function is safe in that
+   it can properly access elements that may not be explicitly
+   represented.  */
+
+HOST_WIDE_INT
+wide_int::extract_to_hwi (int offset, int width) const
+{
+  int start_elt, end_elt, shift;
+  HOST_WIDE_INT x;
+
+  /* Get rid of the easy cases first.   */
+  if (offset >= len * HOST_BITS_PER_WIDE_INT)
+    return sign_mask ();
+  if (offset + width <= 0)
+    return 0;
+
+  shift = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset < 0)
+    {
+      start_elt = -1;
+      end_elt = 0;
+      x = 0;
+    }
+  else
+    {
+      start_elt = offset / HOST_BITS_PER_WIDE_INT;
+      end_elt = (offset + width - 1) / HOST_BITS_PER_WIDE_INT;
+      x = start_elt >= len ? sign_mask () : val[start_elt] >> shift;
+    }
+
+  if (start_elt != end_elt)
+    {
+      HOST_WIDE_INT y = end_elt == len
+	? sign_mask () : val[end_elt];
+
+      x = (unsigned HOST_WIDE_INT)x >> shift;
+      x |= y << (HOST_BITS_PER_WIDE_INT - shift);
+    }
+
+  if (width != HOST_BITS_PER_WIDE_INT)
+    x &= ((HOST_WIDE_INT)1 << width) - 1;
+
+  return x;
+}
+
+
+/* Left shift THIS by CNT.  See the definition of Op.TRUNC for how to
+   set Z.  Since this is used internally, it has the ability to
+   specify the BISIZE and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+wide_int
+wide_int::lshift_large (unsigned int cnt, 
+			unsigned int bs, unsigned int res_prec) const
+{
+  wide_int result;
+  unsigned int i;
+
+  result.bitsize = bs;
+  result.precision = res_prec;
+
+  if (cnt >= res_prec)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+      return result;
+    }
+
+  for (i = 0; i < res_prec; i += HOST_BITS_PER_WIDE_INT)
+    result.val[i / HOST_BITS_PER_WIDE_INT]
+      = extract_to_hwi (i - cnt, HOST_BITS_PER_WIDE_INT);
+
+  result.len = BLOCKS_NEEDED (res_prec);
+  result.canonize ();
+
+  return result;
+}
+
+/* Rotate THIS left by CNT within its precision.  */
+
+wide_int
+wide_int::lrotate (unsigned int cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (cnt, NONE);
+  right = rshiftu (precision - cnt, NONE);
+  result = left | right;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s lrotate %d)\n", result, *this, cnt);
+#endif
+  return result;
+}
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set Z.  */
+
+wide_int
+wide_int::rshiftu_large (unsigned int cnt) const
+{
+  wide_int result;
+  int stop_block, offset, i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (cnt >= precision)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  offset = (precision - cnt) & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset)
+    result.val[stop_block - 1] = zext_hwi (result.val[stop_block - 1], offset);
+  else
+    /* The top block had a 1 at the top position so it will decompress
+       wrong unless a zero block is added.  This only works because we
+       know the shift was greater than 0.  */
+    if (result.val[stop_block - 1] < 0)
+      result.val[result.len++] = 0;
+  return result;
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set Z.  */
+
+wide_int
+wide_int::rshifts_large (unsigned int cnt) const
+{
+  wide_int result;
+  int stop_block, i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (cnt >= precision)
+    {
+      HOST_WIDE_INT m = sign_mask ();
+      result.val[0] = m;
+      result.len = 1;
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  /* No need to sign extend the last block, since it extract_to_hwi
+     already did that.  */
+  return result;
+}
+
+/* Rotate THIS right by CNT within its precision.  */
+
+wide_int
+wide_int::rrotate (unsigned int cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (precision - cnt, NONE);
+  right = rshiftu (cnt, NONE);
+  result = left | right;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s rrotate %d)\n", result, *this, cnt);
+#endif
+  return result;
+}
+
+/*
+ * Private utilities.
+ */
+/* Decompress THIS for at least TARGET bits into a result with bitsize
+   BS and precision PREC.  */
+
+wide_int
+wide_int::decompress (unsigned int target, 
+		      unsigned int bs, unsigned int prec) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (target);
+  HOST_WIDE_INT mask;
+  int len, i;
+
+  result.bitsize = bs;
+  result.precision = prec;
+  result.len = blocks_needed;
+
+  for (i = 0; i < this->len; i++)
+    result.val[i] = val[i];
+
+  len = this->len;
+
+  if (target > result.precision)
+    return result;
+
+  /* The extension that we are doing here is not sign extension, it is
+     decompression.  */
+  mask = sign_mask ();
+  while (len < blocks_needed)
+    result.val[len++] = mask;
+
+  return result;
+}
+
+
+/*
+ * Private debug printing routines.
+ */
+
+/* The debugging routines print results of wide operations into the
+   dump files of the respective passes in which they were called.  */
+char *
+wide_int::dump (char* buf) const
+{
+  int i;
+  int l;
+  const char * sep = "";
+
+  l = sprintf (buf, "[%d,%d (", bitsize, precision);
+  for (i = len - 1; i >= 0; i--)
+    {
+      l += sprintf (&buf[l], "%s" HOST_WIDE_INT_PRINT_HEX, sep, val[i]);
+      sep = " ";
+    }
+
+  gcc_assert (len != 0);
+
+  l += sprintf (&buf[l], ")]");
+
+  gcc_assert (l < MAX_SIZE);
+  return buf;
+}
+
+#ifdef DEBUG_WIDE_INT
+void
+wide_int::debug_vw (const char* fmt, int r, const wide_int& o0)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r, o0.dump (buf0));
+}
+
+void
+wide_int::debug_vwh (const char* fmt, int r, const wide_int &o0,
+		     HOST_WIDE_INT o1)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r, o0.dump (buf0), o1);
+}
+
+void
+wide_int::debug_vww (const char* fmt, int r, const wide_int &o0,
+		     const wide_int &o1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r, o0.dump (buf0), o1.dump (buf1));
+}
+
+void
+wide_int::debug_wh (const char* fmt, const wide_int &r,
+		    HOST_WIDE_INT o1)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o1);
+}
+
+void
+wide_int::debug_whh (const char* fmt, const wide_int &r,
+		     HOST_WIDE_INT o1, HOST_WIDE_INT o2)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o1, o2);
+}
+
+void
+wide_int::debug_wv (const char* fmt, const wide_int &r, int v0)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0);
+}
+
+void
+wide_int::debug_wvv (const char* fmt, const wide_int &r,
+		     int v0, int v1)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0, v1);
+}
+
+void
+wide_int::debug_wvvv (const char* fmt, const wide_int &r,
+		      int v0, int v1, int v2)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0, v1, v2);
+}
+
+void
+wide_int::debug_wvww (const char* fmt, const wide_int &r, int v0,
+		      const wide_int &o0, const wide_int &o1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0,
+	   o0.dump (buf1), o1.dump (buf2));
+}
+
+void
+wide_int::debug_ww (const char* fmt, const wide_int &r,
+		    const wide_int &o0)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1));
+}
+
+void
+wide_int::debug_wwv (const char* fmt, const wide_int &r,
+		     const wide_int &o0, int v0)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1), v0);
+}
+
+void
+wide_int::debug_wwvvs (const char* fmt, const wide_int &r, 
+		       const wide_int &o0, int v0, int v1,
+		       const char *s)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1), v0, v1, s);
+}
+
+void
+wide_int::debug_wwwvv (const char* fmt, const wide_int &r,
+		       const wide_int &o0, const wide_int &o1,
+		       int v0, int v1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), v0, v1);
+}
+
+void
+wide_int::debug_www (const char* fmt, const wide_int &r,
+		     const wide_int &o0, const wide_int &o1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2));
+}
+
+void
+wide_int::debug_wwww (const char* fmt, const wide_int &r,
+		      const wide_int &o0, const wide_int &o1,
+		      const wide_int &o2)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  char buf3[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), o2.dump (buf3));
+}
+#endif
+
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
new file mode 100644
index 0000000..fdd1ddb
--- /dev/null
+++ b/gcc/wide-int.h
@@ -0,0 +1,2340 @@
+/* Operations with very long integers.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef WIDE_INT_H
+#define WIDE_INT_H
+
+/* A wide integer is currently represented as a vector of
+   HOST_WIDE_INTs.  The vector contains enough elements to hold a
+   value of MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT which is
+   a derived for each host target combination.  The values are stored
+   in the vector with the least signicant HOST_BITS_PER_WIDE_INT bits
+   of the value stored in element 0.
+
+   A wide_int contains four fields: the vector (VAL), the bitsize,
+   precision and a length, (LEN).  The length is the number of HWIs
+   needed to represent the value.
+
+   Since most integers used in a compiler are small values, it is
+   generally profitable to use a representation of the value that is
+   shorter than the modes precision.  LEN is used to indicate the
+   number of elements of the vector that are in use.  When LEN *
+   HOST_BITS_PER_WIDE_INT < the precision, the value has been
+   compressed.  The values of the elements of the vector greater than
+   LEN - 1. are all equal to the highest order bit of LEN.
+
+   The representation does not contain any information about
+   signedness of the represented value, so it can be used to represent
+   both signed and unsigned numbers.  For operations where the results
+   depend on signedness (division, comparisons), the signedness must
+   be specified separately.  For operations where the signness
+   matters, one of the operands to the operation specifies either
+   wide_int::SIGNED or wide_int::UNSIGNED.
+
+   All constructors for wide_int take either a bitsize and precision,
+   an enum machine_mode or tree_type.  */
+
+
+#ifndef GENERATOR_FILE
+#include "tree.h"
+#include "hwint.h"
+#include "options.h"
+#include "tm.h"
+#include "insn-modes.h"
+#include "machmode.h"
+#include "double-int.h"
+#include <gmp.h>
+#include "insn-modes.h"
+#include "dumpfile.h"
+
+#define DEBUG_WIDE_INT
+
+class wide_int {
+  /* Internal representation.  */
+  
+  /* VAL is set to a size that is capable of computing a full
+     multiplication on the largest mode that is represented on the
+     target.  The full multiplication is use by tree-vrp.  tree-vpn
+     currently does a 2x largest mode by 2x largest mode yielding a 4x
+     largest mode result.  If operations are added that require larger
+     buffers, then VAL needs to be changed.  */
+  HOST_WIDE_INT val[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  unsigned short len;
+  unsigned int bitsize;
+  unsigned int precision;
+
+ public:
+  enum ShiftOp {
+    NONE,
+    /* There are two uses for the wide-int shifting functions.  The
+       first use is as an emulation of the target hardware.  The
+       second use is as service routines for other optimizations.  The
+       first case needs to be identified by passing TRUNC as the value
+       of ShiftOp so that shift amount is properly handled according to the
+       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
+       amount is always truncated by the bytesize of the mode of
+       THIS.  */
+    TRUNC
+  };
+
+  enum SignOp {
+    /* Many of the math functions produce different results depending
+       on if they are SIGNED or UNSIGNED.  In general, there are two
+       different functions, whose names are prefixed with an 'S" and
+       or an 'U'.  However, for some math functions there is also a
+       routine that does not have the prefix and takes an SignOp
+       parameter of SIGNED or UNSIGNED.  */
+    SIGNED,
+    UNSIGNED
+  };
+
+  /* Conversions.  */
+
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize, 
+				    unsigned int precision);
+  static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize, 
+			     unsigned int precision, bool *overflow);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, unsigned int bitsize, 
+				    unsigned int precision);
+  static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, unsigned int bitsize, 
+			     unsigned int precision, bool *overflow);
+
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type);
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type, 
+				   bool *overflow);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+				    bool *overflow);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+				    enum machine_mode mode);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+				    enum machine_mode mode, 
+				    bool *overflow);
+  static wide_int from_array (const HOST_WIDE_INT* op0,
+			      unsigned int len,
+			      unsigned int bitsize, 
+			      unsigned int precision); 
+  inline static wide_int from_array (const HOST_WIDE_INT* op0,
+				     unsigned int len,
+				     enum machine_mode mode);
+  inline static wide_int from_array (const HOST_WIDE_INT* op0,
+				     unsigned int len,
+				     const_tree type);
+
+  static wide_int from_double_int (double_int, 
+				   unsigned int bitsize, 
+				   unsigned int precision);
+  inline static wide_int from_double_int (double_int, enum machine_mode);
+  static wide_int from_tree (const_tree);
+  static wide_int from_tree_as_infinite_precision (const_tree tcst, 
+						   unsigned int bitsize, 
+						   unsigned int precision);
+  static wide_int from_rtx (const_rtx, enum machine_mode);
+
+  inline HOST_WIDE_INT to_shwi () const;
+  inline HOST_WIDE_INT to_shwi (unsigned int prec) const;
+  inline unsigned HOST_WIDE_INT to_uhwi () const;
+  inline unsigned HOST_WIDE_INT to_uhwi (unsigned int prec) const;
+
+  /* Largest and smallest values that are represented in modes or precisions.  */
+
+  static wide_int max_value (unsigned int prec, unsigned int bitsize, 
+			     unsigned int precision, SignOp sgn);
+  inline static wide_int max_value (unsigned int bitsize, 
+				    unsigned int precision, SignOp sgn);
+  inline static wide_int max_value (const_tree type);
+  inline static wide_int max_value (enum machine_mode mode, SignOp sgn);
+  
+  static wide_int min_value (unsigned int prec, unsigned int bitsize, 
+			     unsigned int precision, SignOp sgn);
+  inline static wide_int min_value (unsigned int bitsize, 
+				    unsigned int precision, SignOp sgn);
+  inline static wide_int min_value (const_tree type);
+  inline static wide_int min_value (enum machine_mode mode, SignOp sgn);
+  
+  /* Small constants */
+
+  inline static wide_int minus_one (unsigned int bitsize, unsigned int prec);
+  inline static wide_int minus_one (const_tree type);
+  inline static wide_int minus_one (enum machine_mode mode);
+  inline static wide_int minus_one (const wide_int &op1);
+  inline static wide_int zero (unsigned int bitsize, unsigned int prec);
+  inline static wide_int zero (const_tree type);
+  inline static wide_int zero (enum machine_mode mode);
+  inline static wide_int zero (const wide_int &op1);
+  inline static wide_int one (unsigned int bitsize, unsigned int prec);
+  inline static wide_int one (const_tree type);
+  inline static wide_int one (enum machine_mode mode);
+  inline static wide_int one (const wide_int &op1);
+  inline static wide_int two (unsigned int bitsize, unsigned int prec);
+  inline static wide_int two (const_tree type);
+  inline static wide_int two (enum machine_mode mode);
+  inline static wide_int two (const wide_int &op1);
+
+  /* Accessors.  */
+
+  inline unsigned short get_len () const;
+  inline unsigned int get_bitsize () const;
+  inline unsigned int get_precision () const;
+  inline HOST_WIDE_INT elt (unsigned int i) const;
+
+  /* Printing functions.  */
+
+  void print_dec (char *buf, SignOp sgn) const;
+  void print_dec (FILE *file, SignOp sgn) const;
+  void print_decs (char *buf) const;
+  void print_decs (FILE *file) const;
+  void print_decu (char *buf) const;
+  void print_decu (FILE *file) const;
+  void print_hex (char *buf) const;
+  void print_hex (FILE *file) const;
+
+  /* Comparative functions.  */
+
+  inline bool minus_one_p () const;
+  inline bool zero_p () const;
+  inline bool one_p () const;
+  inline bool neg_p () const;
+
+  inline bool operator == (const wide_int &y) const;
+  inline bool operator != (const wide_int &y) const;
+  inline bool gt_p (HOST_WIDE_INT x, SignOp sgn) const;
+  inline bool gt_p (const wide_int &x, SignOp sgn) const;
+  inline bool gts_p (HOST_WIDE_INT y) const;
+  inline bool gts_p (const wide_int &y) const;
+  inline bool gtu_p (unsigned HOST_WIDE_INT y) const;
+  inline bool gtu_p (const wide_int &y) const;
+
+  inline bool lt_p (const HOST_WIDE_INT x, SignOp sgn) const;
+  inline bool lt_p (const wide_int &x, SignOp sgn) const;
+  inline bool lts_p (HOST_WIDE_INT y) const;
+  inline bool lts_p (const wide_int &y) const;
+  inline bool ltu_p (unsigned HOST_WIDE_INT y) const;
+  inline bool ltu_p (const wide_int &y) const;
+  inline int cmp (const wide_int &y, SignOp sgn) const;
+  inline int cmps (const wide_int &y) const;
+  inline int cmpu (const wide_int &y) const;
+
+  bool only_sign_bit_p (unsigned int prec) const;
+  inline bool only_sign_bit_p () const;
+  inline bool fits_uhwi_p () const;
+  inline bool fits_shwi_p () const;
+  bool fits_to_tree_p (const_tree type) const;
+  bool fits_u_p (unsigned int prec) const;
+  bool fits_s_p (unsigned int prec) const;
+
+  /* Min and max */
+
+  inline wide_int min (const wide_int &op1, SignOp sgn) const;
+  inline wide_int max (const wide_int &op1, SignOp sgn) const;
+  inline wide_int smin (const wide_int &op1) const;
+  inline wide_int smax (const wide_int &op1) const;
+  inline wide_int umin (const wide_int &op1) const;
+  inline wide_int umax (const wide_int &op1) const;
+
+  /* Extension, these do not change the precision or bitsize.  */
+
+  inline wide_int ext (unsigned int offset, SignOp sgn) const;
+  wide_int sext (unsigned int offset) const;
+  wide_int zext (unsigned int offset) const;
+
+  /* Make a fast copy.  */
+
+  wide_int copy () const;
+
+  /* These change the underlying bitsize and precision.  */
+  
+  wide_int force_to_size (unsigned int bitsize, unsigned int precision, 
+			  SignOp sgn) const;
+  inline wide_int force_to_size (enum machine_mode mode, SignOp sgn) const;
+  inline wide_int force_to_size (const_tree type) const;
+  inline wide_int force_to_size (const_tree type, SignOp sgn) const;
+
+  inline wide_int sforce_to_size (enum machine_mode mode) const;
+  inline wide_int sforce_to_size (const_tree type) const;
+  inline wide_int zforce_to_size (enum machine_mode mode) const;
+  inline wide_int zforce_to_size (const_tree type) const;
+
+  /* Masking, and Insertion  */
+
+  wide_int set_bit (unsigned int bitpos) const;
+  static wide_int set_bit_in_zero (unsigned int, 
+				   unsigned int bitsize, 
+				   unsigned int prec);
+  inline static wide_int set_bit_in_zero (unsigned int, 
+					  enum machine_mode mode);
+  inline static wide_int set_bit_in_zero (unsigned int, const_tree type);
+  wide_int insert (const wide_int &op0, unsigned int offset,
+		   unsigned int width) const;
+  static wide_int mask (unsigned int start, bool negate, 
+			unsigned int bitsize, unsigned int prec);
+  inline static wide_int mask (unsigned int start, bool negate, 
+			       enum machine_mode mode);
+  inline static wide_int mask (unsigned int start, bool negate,
+			       const_tree type);
+  wide_int bswap () const;
+  static wide_int shifted_mask (unsigned int start, unsigned int width,
+				bool negate,
+				unsigned int bitsize, unsigned int prec);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, enum machine_mode mode);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, const_tree type);
+  inline HOST_WIDE_INT sign_mask () const;
+
+  /* Logicals */
+
+  inline wide_int operator & (const wide_int &y) const;
+  inline wide_int and_not (const wide_int &y) const;
+  inline wide_int operator ~ () const;
+  inline wide_int operator | (const wide_int &y) const;
+  inline wide_int or_not (const wide_int &y) const;
+  inline wide_int operator ^ (const wide_int &y) const;
+
+  /* Arithmetic operation functions, alpha sorted.  */
+
+  wide_int abs () const;
+  inline wide_int operator + (const wide_int &y) const;
+  wide_int add (const wide_int &x, SignOp sgn, bool *overflow) const;
+  wide_int clz (unsigned int bitsize, unsigned int prec) const;
+  int clz () const;
+  wide_int clrsb (unsigned int bitsize, unsigned int prec) const;
+  int clrsb () const;
+  wide_int ctz (unsigned int bitsize, unsigned int prec) const;
+  int ctz () const;
+  int exact_log2 () const;
+  int floor_log2 () const;
+  wide_int ffs () const;
+  inline wide_int operator * (const wide_int &y) const;
+  wide_int mul (const wide_int &x, SignOp sgn, bool *overflow) const;
+  inline wide_int smul (const wide_int &x, bool *overflow) const;
+  inline wide_int umul (const wide_int &x, bool *overflow) const;
+  wide_int mul_full (const wide_int &x, SignOp sgn) const;
+  inline wide_int umul_full (const wide_int &x) const;
+  inline wide_int smul_full (const wide_int &x) const;
+  wide_int mul_high (const wide_int &x, SignOp sgn) const;
+  inline wide_int neg () const;
+  inline wide_int neg (bool *overflow) const;
+  wide_int parity (unsigned int bitsize, unsigned int prec) const;
+  int popcount () const;
+  wide_int popcount (unsigned int bitsize, unsigned int prec) const;
+  inline wide_int operator - (const wide_int &y) const;
+  wide_int sub (const wide_int &x, SignOp sgn, bool *overflow) const;
+
+  /* Divison and mod.  These are the ones that are actually used, but
+     there are a lot of them.  */
+
+  wide_int div_trunc (const wide_int &divisor, SignOp sgn) const;
+  wide_int div_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int sdiv_trunc (const wide_int &divisor) const;
+  inline wide_int udiv_trunc (const wide_int &divisor) const;
+
+  wide_int div_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int udiv_floor (const wide_int &divisor) const;
+  inline wide_int sdiv_floor (const wide_int &divisor) const;
+  wide_int div_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  wide_int div_round (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+
+  wide_int divmod_trunc (const wide_int &divisor, wide_int *mod, SignOp sgn) const;
+  inline wide_int sdivmod_trunc (const wide_int &divisor, wide_int *mod) const;
+  inline wide_int udivmod_trunc (const wide_int &divisor, wide_int *mod) const;
+
+  wide_int divmod_floor (const wide_int &divisor, wide_int *mod, SignOp sgn) const;
+  inline wide_int sdivmod_floor (const wide_int &divisor, wide_int *mod) const;
+
+  wide_int mod_trunc (const wide_int &divisor, SignOp sgn) const;
+  wide_int mod_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int smod_trunc (const wide_int &divisor) const;
+  inline wide_int umod_trunc (const wide_int &divisor) const;
+
+  wide_int mod_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int umod_floor (const wide_int &divisor) const;
+  wide_int mod_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  wide_int mod_round (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+
+  /* Shifting rotating and extracting.  */
+  HOST_WIDE_INT extract_to_hwi (int offset, int width) const;
+
+  inline wide_int lshift (const wide_int &y, ShiftOp z = NONE) const;
+  inline wide_int lshift (unsigned int y, ShiftOp z, unsigned int bitsize, 
+			  unsigned int precision) const;
+  inline wide_int lshift (unsigned int y, ShiftOp z = NONE) const;
+
+  inline wide_int lrotate (const wide_int &y) const;
+  wide_int lrotate (unsigned int y) const;
+
+  inline wide_int rshift (const wide_int &y, SignOp sgn, ShiftOp z = NONE) const;
+  inline wide_int rshiftu (const wide_int &y, ShiftOp z = NONE) const;
+  inline wide_int rshiftu (unsigned int y, ShiftOp z = NONE) const;
+  inline wide_int rshifts (const wide_int &y, ShiftOp z = NONE) const;
+  inline wide_int rshifts (unsigned int y, ShiftOp z = NONE) const;
+
+  inline wide_int rrotate (const wide_int &y) const;
+  wide_int rrotate (unsigned int y) const;
+
+  static const int DUMP_MAX = (2 * (MAX_BITSIZE_MODE_ANY_INT / 4
+			       + MAX_BITSIZE_MODE_ANY_INT 
+				    / HOST_BITS_PER_WIDE_INT + 32));
+  char *dump (char* buf) const;
+ private:
+
+  /* 
+   * Internal versions that do the work if the values do not fit in a
+   * HWI.
+   */ 
+
+  /* Comparisons */
+  bool eq_p_large (const wide_int &op1) const;
+  bool lts_p_large (const wide_int &op1) const;
+  int cmps_large (const wide_int &op1) const;
+  bool ltu_p_large (const wide_int &op1) const;
+  int cmpu_large (const wide_int &op1) const;
+
+  /* Logicals.  */
+  wide_int and_large (const wide_int &op1) const;
+  wide_int and_not_large (const wide_int &y) const;
+  wide_int or_large (const wide_int &y) const;
+  wide_int or_not_large (const wide_int &y) const;
+  wide_int xor_large (const wide_int &y) const;
+
+  /* Arithmetic */
+  wide_int add_large (const wide_int &op1) const;
+  wide_int sub_large (const wide_int &op1) const;
+
+  wide_int lshift_large (unsigned int cnt, 
+			 unsigned int bs, unsigned int res_prec) const;
+  wide_int rshiftu_large (unsigned int cnt) const;
+  wide_int rshifts_large (unsigned int cnt) const;
+
+  static wide_int
+    mul_internal (bool high, bool full, 
+		  const wide_int *op1, const wide_int *op2,
+		  wide_int::SignOp sgn,  bool *overflow, bool needs_overflow);
+  static void
+    divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+		       unsigned HOST_HALF_WIDE_INT *b_remainder,
+		       unsigned HOST_HALF_WIDE_INT *b_dividend, 
+		       unsigned HOST_HALF_WIDE_INT *b_divisor, 
+		       int m, int n);
+  static wide_int
+    divmod_internal (bool compute_quotient, 
+		     const wide_int *dividend, const wide_int *divisor,
+		     wide_int::SignOp sgn, wide_int *remainder,
+		     bool compute_remainder, 
+		     bool *overflow);
+
+
+  /* Private utility routines.  */
+  wide_int decompress (unsigned int target, unsigned int bitsize, 
+		       unsigned int precision) const;
+  void canonize ();
+  static inline int trunc_shift (unsigned int bitsize, int cnt);
+  static inline int trunc_shift (unsigned int bitsize, const wide_int &cnt, ShiftOp z);
+
+#ifdef DEBUG_WIDE_INT
+  /* Debugging routines.  */
+  static void debug_vw  (const char* fmt, int r, const wide_int& o0);
+  static void debug_vwh (const char* fmt, int r, const wide_int &o0,
+			 HOST_WIDE_INT o1);
+  static void debug_vww (const char* fmt, int r, const wide_int &o0,
+			 const wide_int &o1);
+  static void debug_wh (const char* fmt, const wide_int &r,
+			 HOST_WIDE_INT o1);
+  static void debug_whh (const char* fmt, const wide_int &r,
+			 HOST_WIDE_INT o1, HOST_WIDE_INT o2);
+  static void debug_wv (const char* fmt, const wide_int &r, int v0);
+  static void debug_wvv (const char* fmt, const wide_int &r, int v0,
+			 int v1);
+  static void debug_wvvv (const char* fmt, const wide_int &r, int v0,
+			  int v1, int v2);
+  static void debug_wvww (const char* fmt, const wide_int &r, int v0,
+			  const wide_int &o0, const wide_int &o1);
+  static void debug_wwv (const char* fmt, const wide_int &r,
+			 const wide_int &o0, int v0);
+  static void debug_wwvvs (const char* fmt, const wide_int &r, 
+			   const wide_int &o0, 
+			   int v0, int v1, const char *s);
+  static void debug_wwwvv (const char* fmt, const wide_int &r,
+			   const wide_int &o0, const wide_int &o1,
+			   int v0, int v1);
+  static void debug_ww (const char* fmt, const wide_int &r,
+			const wide_int &o0);
+  static void debug_www (const char* fmt, const wide_int &r,
+			 const wide_int &o0, const wide_int &o1);
+  static void debug_wwww (const char* fmt, const wide_int &r,
+			  const wide_int &o0, const wide_int &o1, 
+			  const wide_int &o2);
+#endif
+};
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with bitsize
+   and precision taken from MODE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, enum machine_mode mode)
+{
+  return wide_int::set_bit_in_zero (bitpos, GET_MODE_BITSIZE (mode),
+				    GET_MODE_PRECISION (mode));
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with bitsize
+   and precision taken from TYPE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, const_tree type)
+{
+
+  return wide_int::set_bit_in_zero (bitpos, 
+				    GET_MODE_BITSIZE (TYPE_MODE (type)),
+				    TYPE_PRECISION (type));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.   The result is made with bitsize
+   and precision taken from MODE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, enum machine_mode mode)
+{
+  return wide_int::mask (width, negate, 
+			 GET_MODE_BITSIZE (mode),
+			 GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with bitsize
+   and precision taken from TYPE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, const_tree type)
+{
+
+  return wide_int::mask (width, negate, 
+			 GET_MODE_BITSIZE (TYPE_MODE (type)),
+			 TYPE_PRECISION (type));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the bits
+   above that up to the precision are zeros.  The result is inverted
+   if NEGATE is true.  The result is made with bitsize and precision
+   taken from MODE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, enum machine_mode mode)
+{
+  return wide_int::shifted_mask (start, width, negate, 
+				 GET_MODE_BITSIZE (mode),
+				 GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with bitsize
+   and precision taken from TYPE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, const_tree type)
+{
+
+  return wide_int::shifted_mask (start, width, negate, 
+				 GET_MODE_BITSIZE (TYPE_MODE (type)),
+				 TYPE_PRECISION (type));
+}
+
+/* Produce 0 or -1 that is the smear of the sign bit.  */
+
+HOST_WIDE_INT
+wide_int::sign_mask () const
+{
+  int i = len - 1;
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
+	    >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* VRP appears to be badly broken and this is a very ugly fix.  */
+  if (i >= 0)
+    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
+
+  gcc_unreachable ();
+#if 0
+  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
+#endif
+}
+
+/* Conversions */
+
+/* Convert OP0 into a wide_int with parameters taken from TYPE.  */
+
+wide_int
+wide_int::from_hwi (HOST_WIDE_INT op0, const_tree type)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return wide_int::from_uhwi (op0, bitsize, prec);
+  else
+    return wide_int::from_shwi (op0, bitsize, prec);
+}
+
+/* Convert OP0 into a wide_int with parameters taken from TYPE.  If
+   the value does not fit, set OVERFLOW.  */
+
+wide_int
+wide_int::from_hwi (HOST_WIDE_INT op0, const_tree type, 
+		    bool *overflow)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return wide_int::from_uhwi (op0, bitsize, prec, overflow);
+  else
+    return wide_int::from_shwi (op0, bitsize, prec, overflow);
+}
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, unsigned int bitsize, unsigned int precision)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    op0 = sext_hwi (op0, precision);
+
+  result.val[0] = op0;
+  result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wh ("wide_int::from_uhwi %s = " HOST_WIDE_INT_PRINT_HEX "\n", 
+	      result, op0);
+#endif
+
+  return result;
+}
+
+/* Convert signed OP0 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_shwi (op0, bitsize, prec);
+}
+
+/* Convert signed OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+	   bool *overflow)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_shwi (op0, bitsize, prec, overflow);
+}
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0,
+		     unsigned int bitsize, unsigned int precision)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    op0 = zext_hwi (op0, precision);
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && precision > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wh ("wide_int::from_uhwi %s = " HOST_WIDE_INT_PRINT_HEX "\n", 
+	      result, op0);
+#endif
+
+  return result;
+}
+
+/* Convert unsigned OP0 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_uhwi (op0, bitsize, prec);
+}
+
+/* Convert unsigned OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode, 
+		     bool *overflow)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_uhwi (op0, bitsize, prec, overflow);
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = sext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS is too large for
+   the mode's precision, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi () const
+{
+  return to_shwi (precision);
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = zext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS is too large for
+   the mode's precision, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi () const
+{
+  return to_uhwi (precision);
+}
+
+
+/* Convert OP0 of LEN into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT* op0, unsigned int len, 
+		      enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_array (op0, len, bitsize, prec);
+}
+
+/* Convert OP0 of LEN into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT* op0, unsigned int len, 
+		      const_tree type)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return wide_int::from_array (op0, len, bitsize, prec);
+}
+
+/* Convert double_int OP0 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_double_int (double_int op0, enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_double_int (op0, bitsize, prec);
+}
+
+/* Min and Max value helpers.  */
+
+/* Produce the largest SGNed number that is represented in PRECISION.
+   The result is represented in BITSIZE and PRECISION.  SGN must be
+   SIGNED or UNSIGNED.  */
+
+wide_int
+wide_int::max_value (unsigned int bitsize, unsigned int precision, 
+		     SignOp sgn)
+{
+  return max_value (precision, bitsize, precision, sgn);
+}
+  
+/* Produce the largest number that is represented in MODE. The
+   bitsize and precision are taken from mode.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (enum machine_mode mode, SignOp sgn)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+  return max_value (prec, GET_MODE_BITSIZE (mode), prec, sgn);
+}
+
+/* Produce the largest number that is represented in TYPE. The
+   bitsize and precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::max_value (const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  return max_value (prec, GET_MODE_BITSIZE (TYPE_MODE (type)), 
+		    prec, 
+		    TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+/* Produce the smallest SGNed number that is represented in PRECISION.
+   The result is represented in BITSIZE and PRECISION.  SGN must be
+   SIGNED or UNSIGNED.  */
+
+wide_int
+wide_int::min_value (unsigned int bitsize, unsigned int precision, 
+		     SignOp sgn)
+{
+  return min_value (precision, bitsize, precision, sgn);
+}
+  
+/* Produce the smallest number that is represented in MODE. The
+   bitsize and precision are taken from mode.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::min_value (enum machine_mode mode, SignOp sgn)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+  return min_value (prec, GET_MODE_BITSIZE (mode), prec, sgn);
+}
+
+/* Produce the smallest number that is represented in TYPE. The
+   bitsize and precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::min_value (const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  return min_value (prec, GET_MODE_BITSIZE (TYPE_MODE (type)), 
+		    prec, 
+		    TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+
+/* Small constants.  */
+
+/* Return a wide int of -1 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::minus_one (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (-1, bs, prec);
+}
+
+/* Return a wide int of -1 with TYPE.  */
+
+wide_int
+wide_int::minus_one (const_tree type)
+{
+  return wide_int::from_shwi (-1, TYPE_MODE (type));
+}
+
+/* Return a wide int of -1 with MODE.  */
+
+wide_int
+wide_int::minus_one (enum machine_mode mode)
+{
+  return wide_int::from_shwi (-1, mode);
+}
+
+/* Return a wide int of -1 that is the same size as op1.  */
+
+wide_int
+wide_int::minus_one (const wide_int &op1)
+{
+  return wide_int::from_shwi (-1, op1.get_bitsize (), op1.get_precision ());
+}
+
+
+/* Return a wide int of 0 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::zero (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (0, bs, prec);
+}
+
+/* Return a wide int of 0 with TYPE.  */
+
+wide_int
+wide_int::zero (const_tree type)
+{
+  return wide_int::from_shwi (0, TYPE_MODE (type));
+}
+
+/* Return a wide int of 0 with MODE.  */
+
+wide_int
+wide_int::zero (enum machine_mode mode)
+{
+  return wide_int::from_shwi (0, mode);
+}
+
+/* Return a wide int of 0 that is the same size as op1.  */
+
+wide_int
+wide_int::zero (const wide_int &op1)
+{
+  return wide_int::from_shwi (0, op1.get_bitsize (), op1.get_precision ());
+}
+
+
+/* Return a wide int of 1 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::one (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (1, bs, prec);
+}
+
+/* Return a wide int of 1 with TYPE.  */
+
+wide_int
+wide_int::one (const_tree type)
+{
+  return wide_int::from_shwi (1, TYPE_MODE (type));
+}
+
+/* Return a wide int of 1 with MODE.  */
+
+wide_int
+wide_int::one (enum machine_mode mode)
+{
+  return wide_int::from_shwi (1, mode);
+}
+
+/* Return a wide int of 1 that is the same size as op1.  */
+
+wide_int
+wide_int::one (const wide_int &op1)
+{
+  return wide_int::from_shwi (1, op1.get_bitsize (), op1.get_precision ());
+}
+
+
+/* Return a wide int of 2 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::two (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (2, bs, prec);
+}
+
+/* Return a wide int of 2 with TYPE.  */
+
+wide_int
+wide_int::two (const_tree type)
+{
+  return wide_int::from_shwi (2, TYPE_MODE (type));
+}
+
+/* Return a wide int of 2 with MODE.  */
+
+wide_int
+wide_int::two (enum machine_mode mode)
+{
+  return wide_int::from_shwi (2, mode);
+}
+
+/* Return a wide int of 2 that is the same size as op1.  */
+
+wide_int
+wide_int::two (const wide_int &op1)
+{
+  return wide_int::from_shwi (2, op1.get_bitsize (), op1.get_precision ());
+}
+
+/* Public accessors for the interior of a wide int.  */
+
+/* Get the number of host wide ints actually represented within the
+   wide int.  */
+
+unsigned short
+wide_int::get_len () const
+{
+  return len;
+}
+
+/* Get bitsize of the value represented within the wide int.  */
+
+unsigned int
+wide_int::get_bitsize () const
+{
+  return bitsize;
+}
+
+/* Get precision of the value represented within the wide int.  */
+
+unsigned int
+wide_int::get_precision () const
+{
+  return precision;
+}
+
+/* Get a particular element of the wide int.  */
+
+HOST_WIDE_INT
+wide_int::elt (unsigned int i) const
+{
+  return i >= len ? sign_mask () : val[i];
+}
+
+/* Return true if THIS is -1.  */
+
+bool
+wide_int::minus_one_p () const
+{
+  return len == 1 && val[0] == (HOST_WIDE_INT)-1;
+}
+
+/* Return true if THIS is 0.  */
+
+bool
+wide_int::zero_p () const
+{
+  return len == 1 && val[0] == 0;
+}
+
+/* Return true if THIS is 1.  */
+
+bool
+wide_int::one_p () const
+{
+  return len == 1 && val[0] == 1;
+}
+
+/* Return true if THIS is negative.  */
+
+bool
+wide_int::neg_p () const
+{
+  return sign_mask () != 0;
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently signed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+bool
+wide_int::operator == (const wide_int &op1) const
+{
+  bool result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = true;
+      goto ex;
+    }
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << precision) - 1;
+      result = (val[0] & mask) == (op1.val[0] & mask);
+      goto ex;
+    }
+
+  if (precision == HOST_BITS_PER_WIDE_INT)
+    {
+      result = val[0] == op1.val[0];
+      goto ex;
+    }
+
+  result = eq_p_large (op1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s == %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS is not equal to OP1. */ 
+
+bool
+wide_int::operator != (const wide_int &op1) const
+{
+  return !(*this == op1);
+}  
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::lt_p (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (op1);
+  else
+    return ltu_p (op1);
+}  
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::gt_p (HOST_WIDE_INT op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return gts_p (op1);
+  else
+    return gtu_p (op1);
+}  
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::gt_p (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return op1.lts_p (*this);
+  else
+    return op1.ltu_p (*this);
+}  
+
+/* Return true if THIS is signed greater than OP1.  */
+
+bool
+wide_int::gts_p (const wide_int &op1) const
+{
+  return op1.lts_p (*this);
+}  
+
+/* Return true if THIS > OP1 using signed comparisons.  */
+
+bool
+wide_int::gts_p (const HOST_WIDE_INT op1) const
+{
+  bool result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] > sext_hwi (op1, precision);
+      goto ex;
+    }
+  
+  result = !neg_p ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int:: %d = (%s gts_p 0x"HOST_WIDE_INT_PRINT_HEX")\n", 
+	       result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS is unsigned greater than OP1.  */
+
+bool
+wide_int::gtu_p (const wide_int &op1) const
+{
+  return op1.ltu_p (*this);
+}  
+
+/* Return true if THIS > OP1 using unsigned comparisons.  */
+
+bool
+wide_int::gtu_p (const unsigned HOST_WIDE_INT op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  if (precision < HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1, precision);
+
+      result = x0 > x1;
+    }
+  else
+    result = true;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int:: %d = (%s gtu_p 0x"HOST_WIDE_INT_PRINT_HEX")\n", 
+	       result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::lt_p (HOST_WIDE_INT op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (op1);
+  else
+    return ltu_p (op1);
+}  
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p (const HOST_WIDE_INT op1) const
+{
+  bool result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] < sext_hwi (op1, precision);
+      goto ex;
+    }
+  
+  result = neg_p ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int:: %d = (%s lts_p 0x"HOST_WIDE_INT_PRINT_HEX")\n", 
+	       result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p (const wide_int &op1) const
+{
+  bool result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] < op1.val[0];
+      goto ex;
+    }
+
+  result = lts_p_large (op1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s lts_p %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p (const unsigned HOST_WIDE_INT op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  if (precision < HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1, precision);
+
+      result = x0 < x1;
+    }
+  else
+    result = false;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int:: %d = (%s ltu_p 0x"HOST_WIDE_INT_PRINT_HEX")\n", 
+	       result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (op1.val[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = op1.val[0];
+	}
+
+      result = x0 < x1;
+      goto ex;
+    }
+
+  result = ltu_p_large (op1);
+
+ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s ltu_p %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return -1 0 or 1 depending on how THIS compares with OP1.  Signness
+   is indicated by OP.  */
+
+int
+wide_int::cmp (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return cmps (op1);
+  else
+    return cmpu (op1);
+}  
+
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+int
+wide_int::cmps (const wide_int &op1) const
+{
+  int result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = 0;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      if (val[0] < op1.val[0])
+	{
+	  result = -1;
+	  goto ex;
+	}
+      if (val[0] > op1.val[0])
+	{
+	  result = 1;
+	  goto ex;
+	}
+    }
+
+  result = cmps_large (op1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s cmps %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+int
+wide_int::cmpu (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = 0;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (op1.val[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = op1.val[0];
+	}
+
+      if (x0 < x1)
+	result = -1;
+      else if (x0 == x1)
+	result = 0;
+      else
+	result = 1;
+      goto ex;
+    }
+
+  result = cmpu_large (op1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s cmpu %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+
+/* Return the signed or unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::min (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return lts_p (op1) ? (*this) : op1;
+  else
+    return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed or unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::max (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return gts_p (op1) ? (*this) : op1;
+  else
+    return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed min of THIS and OP1. */
+
+wide_int
+wide_int::smin (const wide_int &op1) const
+{
+  return lts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed max of THIS and OP1. */
+
+wide_int
+wide_int::smax (const wide_int &op1) const
+{
+  return gts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::umin (const wide_int &op1) const
+{
+  return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::umax (const wide_int &op1) const
+{
+  return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p () const
+{
+  return only_sign_bit_p (precision);
+}
+
+/* Return true if THIS fits in a HOST_WIDE_INT with no loss of
+   precision.  */
+
+bool
+wide_int::fits_shwi_p () const
+{
+  return len == 1;
+}
+
+/* Return true if THIS fits in an unsigned HOST_WIDE_INT with no loss
+   of precision.  */
+
+bool
+wide_int::fits_uhwi_p () const
+{
+  return len == 1 
+    || (len == 2 && val[1] == 0);
+}
+
+/* Return THIS extended to PREC.  The signness of the extension is
+   specified by OP.  */
+
+wide_int 
+wide_int::ext (unsigned int prec, SignOp z) const
+{
+  if (z == UNSIGNED)
+    return zext (prec);
+  else
+    return sext (prec);
+}
+
+/* Return THIS forced to the bitsize and precision of TYPE.  If this
+   is extension, the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (enum machine_mode mode, SignOp sgn) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (bitsize, prec, sgn);
+}
+
+/* Return THIS forced to the bitsize, precision and sign of TYPE.  If
+   this is extension, the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (const_tree type) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+  SignOp sgn = TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED;
+
+  return force_to_size (bitsize, prec, sgn);
+}
+
+/* Return THIS zero extended to the bitsize and precision of TYPE but
+   extends using SGN.  If this is extension, the sign is set by
+   SGN. */
+
+wide_int 
+wide_int::force_to_size (const_tree type, SignOp sgn) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (bitsize, prec, sgn);
+}
+
+/* Return THIS forced to the bitsize and precision of TYPE.  If this
+   is extension, it is signed. */
+
+wide_int 
+wide_int::sforce_to_size (enum machine_mode mode) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (bitsize, prec, SIGNED);
+}
+
+/* Return THIS zero extended to the bitsize and precision of TYPE but
+   extends using SGN.  If this is extension, it is signed. */
+
+wide_int 
+wide_int::sforce_to_size (const_tree type) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (bitsize, prec, SIGNED);
+}
+
+/* Return THIS forced to the bitsize and precision of TYPE.  If this
+   is extension, it is unsigned. */
+
+wide_int 
+wide_int::zforce_to_size (enum machine_mode mode) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (bitsize, prec, UNSIGNED);
+}
+
+/* Return THIS zero extended to the bitsize and precision of TYPE but
+   extends using SGN.  If this is extension, it is unsigned. */
+
+wide_int 
+wide_int::zforce_to_size (const_tree type) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (bitsize, prec, UNSIGNED);
+}
+
+/*
+ * Logicals.
+ */
+
+/* Return THIS & OP1.  */
+
+wide_int
+wide_int::operator & (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] & op1.val[0];
+    }
+  else
+    result = and_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s & %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+
+/* Return THIS & ~OP1.  */
+
+wide_int
+wide_int::and_not (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] & ~op1.val[0];
+    }
+  else
+    result = and_not_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s &~ %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+
+/* Return the logical negation (bitwise complement) of THIS.  */
+
+wide_int
+wide_int::operator ~ () const
+{
+  wide_int result;
+  int l0 = len - 1;
+
+  result.len = len;
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = ~val[l0];
+      l0--;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = (~ %s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+wide_int
+wide_int::operator | (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] | op1.val[0];
+    }
+  else
+    result = or_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s | %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+
+/* Return THIS | ~OP1.  */
+
+wide_int
+wide_int::or_not (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] | ~op1.val[0];
+    }
+  else
+    result = or_not_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s |~ %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+
+/* Return THIS ^ OP1.  */
+
+wide_int
+wide_int::operator ^ (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] ^ op1.val[0];
+    }
+  else
+    result = xor_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s ^ %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/*
+ * Integer arithmetic
+ */
+
+/* Return THIS + OP1.  */
+
+wide_int
+wide_int::operator + (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] + op1.val[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = add_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s + %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Multiply THIS and OP1.  The result is the same precision as the
+   operands, so there is no reason for signed or unsigned
+   versions.  */
+
+wide_int
+wide_int::operator * (const wide_int &op1) const
+{
+  bool overflow = false;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      wide_int result;
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] * op1.val[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_www ("wide_int:: %s = (%s * %s)\n", result, *this, op1);
+#endif
+      return result;
+    }
+  else
+    return mul_internal (false, false, this, &op1, UNSIGNED, &overflow, false);
+}
+
+/* Negate THIS.  */
+
+wide_int
+wide_int::neg () const
+{
+  wide_int z = wide_int::from_shwi (0, bitsize, precision);
+  return z - *this;
+}
+
+/* Negate THIS.  Set overflow if the value cannot be negated.  */
+
+wide_int
+wide_int::neg (bool *overflow) const
+{
+  wide_int z = wide_int::from_shwi (0, bitsize, precision);
+  if (only_sign_bit_p ())
+    *overflow = true;
+
+  return z - *this;
+}
+
+/* Return THIS - OP1.  */
+
+wide_int
+wide_int::operator - (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] - op1.val[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = sub_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s - %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+
+/* Signed multiply THIS and OP1.  The result is the same precision as
+   the operands.  OVERFLOW is set true if the result overflows.  */
+
+wide_int
+wide_int::smul (const wide_int &x, bool *overflow) const
+{
+  return mul (x, SIGNED, overflow);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is the same precision
+   as the operands.  OVERFLOW is set true if the result overflows.  */
+
+wide_int
+wide_int::umul (const wide_int &x, bool *overflow) const
+{
+  return mul (x, UNSIGNED, overflow);
+}
+
+/* Signed multiply THIS and OP1.  The result is twice the precision as
+   the operands.  */
+
+wide_int
+wide_int::smul_full (const wide_int &x) const
+{
+  return mul_full (x, SIGNED);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is twice the precision
+   as the operands.  */
+
+wide_int
+wide_int::umul_full (const wide_int &x) const
+{
+  return mul_full (x, UNSIGNED);
+}
+
+/* Signed divide with truncation of result.  */
+
+wide_int
+wide_int::sdiv_trunc (const wide_int &divisor) const
+{
+  return div_trunc (divisor, SIGNED);
+}
+
+/* Unsigned divide with truncation of result.  */
+
+wide_int
+wide_int::udiv_trunc (const wide_int &divisor) const
+{
+  return div_trunc (divisor, UNSIGNED);
+}
+
+/* Unsigned divide with floor truncation of result.  */
+
+wide_int
+wide_int::udiv_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return div_floor (divisor, UNSIGNED, &overflow);
+}
+
+/* Signed divide with floor truncation of result.  */
+
+wide_int
+wide_int::sdiv_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return div_floor (divisor, SIGNED, &overflow);
+}
+
+/* Signed divide/mod with truncation of result.  */
+
+wide_int
+wide_int::sdivmod_trunc (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_trunc (divisor, mod, SIGNED);
+}
+
+/* Unsigned divide/mod with truncation of result.  */
+
+wide_int
+wide_int::udivmod_trunc (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_trunc (divisor, mod, UNSIGNED);
+}
+
+/* Signed divide/mod with floor truncation of result.  */
+
+wide_int
+wide_int::sdivmod_floor (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_floor (divisor, mod, SIGNED);
+}
+
+/* Signed mod with truncation of result.  */
+
+wide_int
+wide_int::smod_trunc (const wide_int &divisor) const
+{
+  return mod_trunc (divisor, SIGNED);
+}
+
+/* Unsigned mod with truncation of result.  */
+
+wide_int
+wide_int::umod_trunc (const wide_int &divisor) const
+{
+  return mod_trunc (divisor, UNSIGNED);
+}
+
+/* Unsigned mod with floor truncation of result.  */
+
+wide_int
+wide_int::umod_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return mod_floor (divisor, UNSIGNED, &overflow);
+}
+
+/* If SHIFT_COUNT_TRUNCATED is defined, truncate CNT.   
+
+   At first look, the shift truncation code does not look right.
+   Shifts (and rotates) are done according to the precision of the
+   mode but the shift count is truncated according to the bitsize
+   of the mode.   This is how real hardware works.
+
+   On an ideal machine, like Knuth's mix machine, a shift count is a
+   word long and all of the bits of that word are examined to compute
+   the shift amount.  But on real hardware, especially on machines
+   with fast (single cycle shifts) that takes too long.  On these
+   machines, the amount of time to perform a shift dictates the cycle
+   time of the machine so corners are cut to keep this fast.  A
+   comparison of an entire 64 bit word would take something like 6
+   gate delays before the shifting can even start.
+
+   So real hardware only looks at a small part of the shift amount.
+   On ibm machines, this tends to be 1 more than what is necessary to
+   encode the shift amount.  The rest of the world looks at only the
+   minimum number of bits.  This means that only 3 gate delays are
+   necessary to set up the shifter.
+
+   On the other hand, right shifts and rotates must be according to
+   the precision or the operation does not make any sense.   */
+inline int
+wide_int::trunc_shift (unsigned int bitsize, int cnt)
+{
+#ifdef SHIFT_COUNT_TRUNCATED
+  cnt = cnt & (bitsize - 1);
+#endif
+  return cnt;
+}
+
+/* This function is called in two contexts.  If OP == TRUNC, this
+   function provides a count that matches the semantics of the target
+   machine depending on the value of SHIFT_COUNT_TRUNCATED.  Note that
+   if SHIFT_COUNT_TRUNCATED is not defined, this function may produce
+   -1 as a value if the shift amount is greater than the bitsize of
+   the mode.  -1 is a surrogate for a very large amount.
+
+   If OP == NONE, then this function always truncates the shift value
+   to the bitsize because this shifting operation is a function that
+   is internal to GCC.  */
+
+inline int
+wide_int::trunc_shift (unsigned int bitsize, const wide_int &cnt, ShiftOp z)
+{
+  if (z == TRUNC)
+    {
+#ifdef SHIFT_COUNT_TRUNCATED
+      return cnt.val[0] & (bitsize - 1);
+#else
+      if (cnt.ltu (bitsize))
+	return cnt.val[0] & (bitsize - 1);
+      else 
+	return -1;
+#endif
+    }
+  else
+    return cnt.val[0] & (bitsize - 1);
+}
+
+/* Left shift by an integer Y.  See the definition of Op.TRUNC for how
+   to set Z.  */
+
+wide_int
+wide_int::lshift (unsigned int y, ShiftOp z) const
+{
+  return lshift (y, z, bitsize, precision);
+}
+
+/* Left shifting by an wide_int shift amount.  See the definition of
+   Op.TRUNC for how to set Z.  */
+
+wide_int
+wide_int::lshift (const wide_int &y, ShiftOp z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (bitsize, y, TRUNC);
+      if (shift == -1)
+	return wide_int::zero (bitsize, precision);
+      return lshift (shift, NONE, bitsize, precision);
+    }
+  else
+    return lshift (trunc_shift (bitsize, y, NONE), NONE, bitsize, precision);
+}
+
+/* Left shift THIS by CNT.  See the definition of Op.TRUNC for how to
+   set Z.  Since this is used internally, it has the ability to
+   specify the BISIZE and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+wide_int
+wide_int::lshift (unsigned int cnt, ShiftOp op, 
+		  unsigned int bs, unsigned int res_prec) const
+{
+  wide_int result;
+
+  if (op == TRUNC)
+    cnt = trunc_shift (bs, cnt);
+
+  /* Handle the simple case quickly.   */
+  if (res_prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.bitsize = bs;
+      result.precision = res_prec;
+      result.len = 1;
+      result.val[0] = val[0] << cnt;
+    }
+  else
+    result = lshift_large (cnt, bs, res_prec);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s << %d)\n", result, *this, cnt);
+#endif
+
+  return result;
+}
+
+/* Rotate THIS left by Y within its precision.  */
+
+wide_int
+wide_int::lrotate (const wide_int &y) const
+{
+  return lrotate (y.val[0]);
+}
+
+
+/* Unsigned right shift by Y.  See the definition of Op.TRUNC for how
+   to set Z.  */
+
+wide_int
+wide_int::rshiftu (const wide_int &y, ShiftOp z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (bitsize, y, TRUNC);
+      if (shift == -1)
+	return wide_int::zero (bitsize, precision);
+      return rshiftu (shift, NONE);
+    }
+  else
+    return rshiftu (trunc_shift (bitsize, y, NONE), NONE);
+}
+
+/* Right shift THIS by Y.  SGN indicates the sign.  Z indicates the
+   truncation option.  */
+
+wide_int
+wide_int::rshift (const wide_int &y, SignOp sgn, ShiftOp z) const
+{
+  if (sgn == UNSIGNED)
+    return rshiftu (y, z);
+  else
+    return rshifts (y, z);
+}
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set Z.  */
+
+wide_int
+wide_int::rshiftu (unsigned int cnt, ShiftOp trunc_op) const
+{
+  wide_int result;
+
+  if (trunc_op == TRUNC)
+    cnt = trunc_shift (bitsize, cnt);
+
+  if (cnt == 0)
+    result = copy ();
+  
+  else if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* Handle the simple case quickly.   */
+      unsigned HOST_WIDE_INT x = val[0];
+
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.len = 1;
+
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	x = zext_hwi (x, precision);
+
+      result.val[0] = x >> cnt;
+    }
+  else 
+    result = rshiftu_large (cnt);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s >>U %d)\n", result, *this, cnt);
+#endif
+  return result;
+}
+
+/* Signed right shift by Y.  See the definition of Op.TRUNC for how to
+   set Z.  */
+wide_int
+wide_int::rshifts (const wide_int &y, ShiftOp z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (bitsize, y, TRUNC);
+      if (shift == -1)
+	{
+	  /* The value of the shift was larger than the bitsize and this
+	     machine does not truncate the value, so the result is
+	     a smeared sign bit.  */
+	  if (neg_p ())
+	    return wide_int::minus_one (bitsize, precision);
+	  else
+	    return wide_int::zero (bitsize, precision);
+	}
+      return rshifts (shift, NONE);
+    }
+  else
+    return rshifts (trunc_shift (bitsize, y, NONE), NONE);
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set Z.  */
+
+wide_int
+wide_int::rshifts (unsigned int cnt, ShiftOp trunc_op) const
+{
+  wide_int result;
+
+  if (trunc_op == TRUNC)
+    cnt = trunc_shift (bitsize, cnt);
+
+  if (cnt == 0)
+    result = copy ();
+  else if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* Handle the simple case quickly.   */
+      HOST_WIDE_INT x = val[0];
+
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.len = 1;
+      result.val[0] = x >> cnt;
+    }
+  else
+    result = rshifts_large (cnt);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s >>S %d)\n", result, *this, cnt);
+#endif
+  return result;
+}
+
+/* Rotate THIS right by Y within its precision.  */
+
+wide_int
+wide_int::rrotate (const wide_int &y) const
+{
+  return rrotate (y.val[0]);
+}
+
+/* tree related routines.  */
+
+extern tree wide_int_to_tree (tree type, const wide_int &cst);
+extern tree wide_int_to_infinite_tree (tree type, const wide_int &cst, 
+				       unsigned int prec);
+extern tree force_fit_type_wide (tree, const wide_int &, int, bool);
+#if 0
+extern wide_int mem_ref_offset (const_tree);
+#endif
+
+/* Conversion to and from GMP integer representations.  */
+
+void mpz_set_wide_int (mpz_t, wide_int, bool);
+wide_int mpz_get_wide_int (const_tree, mpz_t, bool);
+#endif /* GENERATOR FILE */
+
+#endif /* WIDE_INT_H */

[-- Attachment #3: p4-3.clog --]
[-- Type: text/plain, Size: 243 bytes --]

2012-11-30  Kenneth Zadeck <zadeck@naturalbridge.com>

	* Makefile.in (wide-int.c, wide-int.h): New files.
	* wide-int.c: New file containing implementation of wide_int class.
	* wide-int.h: New file containing public spec for wide_int class.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 5th patch - the rtl level changes
  2012-11-30 16:46                                                                         ` patch to fix constant math - 4th patch - the wide-int class Kenneth Zadeck
@ 2012-11-30 17:00                                                                           ` Kenneth Zadeck
  2012-11-30 18:13                                                                             ` patch to add storage classes to wide int Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2012-11-30 17:00 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, Lawrence Crowl, Richard Sandiford

[-- Attachment #1: Type: text/plain, Size: 267 bytes --]

This is an updated version of the rtl level changes for wide-int.

not much has changed since the previous iteration.   Patch rot has been 
fixed and a set of comments by Richard Sandiford have all been resolved 
as requested.

This patch depends on patch 4.

kenny


[-- Attachment #2: p5-2.clog --]
[-- Type: text/plain, Size: 4577 bytes --]

2012-11-30  Kenneth Zadeck <zadeck@naturalbridge.com>

	* alias.c  (rtx_equal_for_memref_p): Fixed comment.
	* builtins.c (c_getstr, c_readstr, expand_builtin_signbit): 
	Make to work with any size int.
	* combine.c (try_combine, subst): Changed to support any 
	size integer.
	* coretypes.h (hwivec_def, hwivec, const_hwivec): New.
	* cse.c (hash_rtx_cb): Added CONST_WIDE_INT case are
	modified DOUBLE_INT case.
	* cselib.c (rtx_equal_for_cselib_1): Converted cases to 
	CASE_CONST_UNIQUE.
	(cselib_hash_rtx): Added CONST_WIDE_INT case.
	* defaults.h (TARGET_SUPPORTS_WIDE_INT): New.
	* doc/rtl.texi (CONST_DOUBLE, CONST_WIDE_INT): Updated.
	* doc/tm.texi (TARGET_SUPPORTS_WIDE_INT): New.	
	* doc/tm.texi.in (TARGET_SUPPORTS_WIDE_INT): New.
	* dojump.c (prefer_and_bit_test): Use wide int api.
	* dwarf2out.c (get_full_len): New function.
	(dw_val_equal_p, size_of_loc_descr,
	output_loc_operands, print_die, attr_checksum, same_dw_val_p,
	size_of_die, value_format, output_die, mem_loc_descriptor,
	loc_descriptor, extract_int, add_const_value_attribute,
	hash_loc_operands, compare_loc_operands): Add support for wide-ints.
	(add_AT_wide): New function.
	* dwarf2out.h (enum dw_val_class): Added dw_val_class_wide_int.
	* emit-rtl.c (const_wide_int_htab): Add marking.
	(const_wide_int_htab_hash, const_wide_int_htab_eq,
	lookup_const_wide_int, immed_wide_int_const): New functions.
	(const_double_htab_hash, const_double_htab_eq,
	rtx_to_double_int, immed_double_const): Conditionally 
	changed CONST_DOUBLE behavior.
 	(immed_double_const, init_emit_once): Changed to support wide-int.
	* explow.c (plus_constant): Now uses wide-int api.
	* expmed.c (mask_rtx, lshift_value): Now uses wide-int.
 	(expand_mult, expand_smod_pow2): Make to work with any size int.
	(make_tree): Added CONST_WIDE_INT case.
	* expr.c (convert_modes): Added support for any size int.
	(emit_group_load_1): Added todo for place that still does not
	allow large ints.
	(store_expr, expand_constructor): Fixed comments.
	(expand_expr_real_2, expand_expr_real_1,
	reduce_to_bit_field_precision, const_vector_from_tree):
	Converted to use wide-int api.
	* final.c (output_addr_const): Added CONST_WIDE_INT case.
	* genemit.c (gen_exp): Added CONST_WIDE_INT case.
	* gengenrtl.c (excluded_rtx): Added CONST_WIDE_INT case.
	* gengtype.c (wide-int): New type.
	* genpreds.c (write_one_predicate_function): Fixed comment.
	(add_constraint): Added CONST_WIDE_INT test.
	(write_tm_constrs_h): Do not emit hval or lval if target
	supports wide integers.
	* gensupport.c (const_wide_int_operand,
	const_scalar_int_operand): New.
	* ggc-zone.c (ggc_alloc_typed_stat): Added
	gt_ggc_e_10hwivec_def case.
	* ggc.h (ggc_alloc_hwivec_sized): New.
	* optabs.c (expand_subword_shift, expand_doubleword_shift,
	expand_absneg_bit, expand_absneg_bit, expand_copysign_absneg,
	expand_copysign_bit): Made to work with any size int.  
	* postreload.c (reload_cse_simplify_set):  Now uses wide-int api.
	* print-rtl.c (print_rtx): Added CONST_WIDE_INT case.
	* read-rtl.c (validate_const_wide_int): New function.
	(read_rtx_code): Added CONST_WIDE_INT case.
	* recog.c (const_scalar_int_operand, const_double_operand):
	New versions if target supports wide integers.
	(const_wide_int_operand): New function.
	* rtl.c (DEF_RTL_EXPR): Added CONST_WIDE_INT case.
	(rtx_size): Ditto.
	(rtx_alloc_stat, hwivec_output_hex, hwivec_check_failed_bounds):
	New functions.
	(iterative_hash_rtx): Added CONST_WIDE_INT case.
	* rtl.def (CONST_WIDE_INT): New.
	* rtl.h (hwivec_def): New function.
	(HWI_GET_NUM_ELEM, HWI_PUT_NUM_ELEM, CONST_WIDE_INT_P,
	CONST_SCALAR_INT_P, XHWIVEC_ELT, HWIVEC_CHECK, CONST_WIDE_INT_VEC,
	CONST_WIDE_INT_NUNITS, CONST_WIDE_INT_ELT, rtx_alloc_v): New macros.
	(chain_next): Added hwiv case.
	(CASE_CONST_SCALAR_INT, CONST_INT, CONST_WIDE_INT):  Added new
	defs if target supports wide ints.
	* rtlanal.c (commutative_operand_precedence, split_double):
	Added CONST_WIDE_INT case.
	* sched-vis.c (print_value): Added CONST_WIDE_INT case are
	modified DOUBLE_INT case.
	* sel-sched-ir.c (lhs_and_rhs_separable_p): Fixed comment
	* simplify-rtx.c (mode_signbit_p,
	simplify_const_unary_operation, simplify_binary_operation_1,
	simplify_const_binary_operation,
	simplify_const_relational_operation, simplify_immed_subreg):
	Make work with any size int.  .
	* tree-ssa-address.c (addr_for_mem_ref): Changes to use
	wide-int rather than double-int.
	* tree.c (wide_int_to_tree): New function.
	* var-tracking.c (loc_cmp): Added CONST_WIDE_INT case.
	* varasm.c (const_rtx_hash_1): Added CONST_WIDE_INT case.

[-- Attachment #3: p5-2.diff --]
[-- Type: text/x-patch, Size: 136288 bytes --]

diff --git a/gcc/alias.c b/gcc/alias.c
index 15fd7f3..fd9b85a 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -1487,9 +1487,7 @@ rtx_equal_for_memref_p (const_rtx x, const_rtx y)
 
     case VALUE:
     CASE_CONST_UNIQUE:
-      /* There's no need to compare the contents of CONST_DOUBLEs or
-	 CONST_INTs because pointer equality is a good enough
-	 comparison for these nodes.  */
+      /* Pointer equality guarantees equality for these nodes.  */
       return 0;
 
     default:
diff --git a/gcc/builtins.c b/gcc/builtins.c
index fb7b537..5415cf4 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -671,20 +671,24 @@ c_getstr (tree src)
   return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
 }
 
-/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
+/* Return a constant integer corresponding to target reading
    GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
 
 static rtx
 c_readstr (const char *str, enum machine_mode mode)
 {
-  HOST_WIDE_INT c[2];
+  wide_int c;
   HOST_WIDE_INT ch;
   unsigned int i, j;
+  HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  unsigned int len = (GET_MODE_PRECISION (mode) + HOST_BITS_PER_WIDE_INT - 1)
+    / HOST_BITS_PER_WIDE_INT;
+
+  for (i = 0; i < len; i++)
+    tmp[i] = 0;
 
   gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
 
-  c[0] = 0;
-  c[1] = 0;
   ch = 1;
   for (i = 0; i < GET_MODE_SIZE (mode); i++)
     {
@@ -695,13 +699,14 @@ c_readstr (const char *str, enum machine_mode mode)
 	  && GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
 	j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
       j *= BITS_PER_UNIT;
-      gcc_assert (j < HOST_BITS_PER_DOUBLE_INT);
 
       if (ch)
 	ch = (unsigned char) str[i];
-      c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
+      tmp[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
     }
-  return immed_double_const (c[0], c[1], mode);
+  
+  c = wide_int::from_array (tmp, len, mode);
+  return immed_wide_int_const (c, mode);
 }
 
 /* Cast a target constant CST to target CHAR and if that value fits into
@@ -4998,12 +5003,12 @@ expand_builtin_signbit (tree exp, rtx target)
 
   if (bitpos < GET_MODE_BITSIZE (rmode))
     {
-      double_int mask = double_int_zero.set_bit (bitpos);
+      wide_int mask = wide_int::set_bit_in_zero (bitpos, rmode);
 
       if (GET_MODE_SIZE (imode) > GET_MODE_SIZE (rmode))
 	temp = gen_lowpart (rmode, temp);
       temp = expand_binop (rmode, and_optab, temp,
-			   immed_double_int_const (mask, rmode),
+			   immed_wide_int_const (mask, rmode),
 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
   else
diff --git a/gcc/combine.c b/gcc/combine.c
index df5414a..13f2c44 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -2660,23 +2660,15 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
 	    offset = -1;
 	}
 
-      if (offset >= 0
-	  && (GET_MODE_PRECISION (GET_MODE (SET_DEST (temp)))
-	      <= HOST_BITS_PER_DOUBLE_INT))
+      if (offset >= 0)
 	{
-	  double_int m, o, i;
+	  wide_int o;
 	  rtx inner = SET_SRC (PATTERN (i3));
 	  rtx outer = SET_SRC (temp);
-
-	  o = rtx_to_double_int (outer);
-	  i = rtx_to_double_int (inner);
-
-	  m = double_int::mask (width);
-	  i &= m;
-	  m = m.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
-	  i = i.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
-	  o = o.and_not (m) | i;
-
+	  
+	  o = (wide_int::from_rtx (outer, GET_MODE (SET_DEST (temp)))
+	       .insert (wide_int::from_rtx (inner, GET_MODE (dest)),
+			offset, width));
 	  combine_merges++;
 	  subst_insn = i3;
 	  subst_low_luid = DF_INSN_LUID (i2);
@@ -2687,8 +2679,8 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
 	  /* Replace the source in I2 with the new constant and make the
 	     resulting insn the new pattern for I3.  Then skip to where we
 	     validate the pattern.  Everything was set up above.  */
-	  SUBST (SET_SRC (temp),
-		 immed_double_int_const (o, GET_MODE (SET_DEST (temp))));
+	  SUBST (SET_SRC (temp), 
+		 immed_wide_int_const (o, GET_MODE (SET_DEST (temp))));
 
 	  newpat = PATTERN (i2);
 
@@ -5106,7 +5098,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
 		  if (! x)
 		    x = gen_rtx_CLOBBER (mode, const0_rtx);
 		}
-	      else if (CONST_INT_P (new_rtx)
+	      else if (CONST_SCALAR_INT_P (new_rtx)
 		       && GET_CODE (x) == ZERO_EXTEND)
 		{
 		  x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 3bc2f40..e58d16b 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -56,6 +56,9 @@ typedef const struct rtx_def *const_rtx;
 struct rtvec_def;
 typedef struct rtvec_def *rtvec;
 typedef const struct rtvec_def *const_rtvec;
+struct hwivec_def;
+typedef struct hwivec_def *hwivec;
+typedef const struct hwivec_def *const_hwivec;
 union tree_node;
 typedef union tree_node *tree;
 union gimple_statement_d;
diff --git a/gcc/cse.c b/gcc/cse.c
index ff91b9d..7ad186c 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -2333,15 +2333,23 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
                + (unsigned int) INTVAL (x));
       return hash;
 
+    case CONST_WIDE_INT:
+      {
+	int i;
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hash += CONST_WIDE_INT_ELT (x, i);
+      }
+      return hash;
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
 	 the integers representing the constant.  */
       hash += (unsigned int) code + (unsigned int) GET_MODE (x);
-      if (GET_MODE (x) != VOIDmode)
-	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      else
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	hash += ((unsigned int) CONST_DOUBLE_LOW (x)
 		 + (unsigned int) CONST_DOUBLE_HIGH (x));
+      else
+	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       return hash;
 
     case CONST_FIXED:
@@ -3758,6 +3766,7 @@ equiv_constant (rtx x)
 
       /* See if we previously assigned a constant value to this SUBREG.  */
       if ((new_rtx = lookup_as_function (x, CONST_INT)) != 0
+	  || (new_rtx = lookup_as_function (x, CONST_WIDE_INT)) != 0
           || (new_rtx = lookup_as_function (x, CONST_DOUBLE)) != 0
           || (new_rtx = lookup_as_function (x, CONST_FIXED)) != 0)
         return new_rtx;
diff --git a/gcc/cselib.c b/gcc/cselib.c
index b7b2b63..9017c78 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -925,8 +925,7 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, enum machine_mode memmode)
   /* These won't be handled correctly by the code below.  */
   switch (GET_CODE (x))
     {
-    case CONST_DOUBLE:
-    case CONST_FIXED:
+    CASE_CONST_UNIQUE:
     case DEBUG_EXPR:
       return 0;
 
@@ -1120,15 +1119,23 @@ cselib_hash_rtx (rtx x, int create, enum machine_mode memmode)
       hash += ((unsigned) CONST_INT << 7) + INTVAL (x);
       return hash ? hash : (unsigned int) CONST_INT;
 
+    case CONST_WIDE_INT:
+      {
+	int i;
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hash += CONST_WIDE_INT_ELT (x, i);
+      }
+      return hash;
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
 	 the integers representing the constant.  */
       hash += (unsigned) code + (unsigned) GET_MODE (x);
-      if (GET_MODE (x) != VOIDmode)
-	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      else
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	hash += ((unsigned) CONST_DOUBLE_LOW (x)
 		 + (unsigned) CONST_DOUBLE_HIGH (x));
+      else
+	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       return hash ? hash : (unsigned int) CONST_DOUBLE;
 
     case CONST_FIXED:
diff --git a/gcc/defaults.h b/gcc/defaults.h
index 76909ab..993aa99 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -1406,6 +1406,14 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define SWITCHABLE_TARGET 0
 #endif
 
+/* If the target supports integers that are wider than two
+   HOST_WIDE_INTs on the host compiler, then the target should define
+   TARGET_SUPPORTS_WIDE_INT and make the appropriate fixups.
+   Otherwise the compiler really is not robust.  */
+#ifndef TARGET_SUPPORTS_WIDE_INT
+#define TARGET_SUPPORTS_WIDE_INT 0
+#endif
+
 #endif /* GCC_INSN_FLAGS_H  */
 
 #endif  /* ! GCC_DEFAULTS_H */
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 6842cb8..c6d0f86 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -1533,17 +1533,22 @@ Similarly, there is only one object for the integer whose value is
 
 @findex const_double
 @item (const_double:@var{m} @var{i0} @var{i1} @dots{})
-Represents either a floating-point constant of mode @var{m} or an
-integer constant too large to fit into @code{HOST_BITS_PER_WIDE_INT}
-bits but small enough to fit within twice that number of bits (GCC
-does not provide a mechanism to represent even larger constants).  In
-the latter case, @var{m} will be @code{VOIDmode}.  For integral values
-constants for modes with more bits than twice the number in
-@code{HOST_WIDE_INT} the implied high order bits of that constant are
-copies of the top bit of @code{CONST_DOUBLE_HIGH}.  Note however that
-integral values are neither inherently signed nor inherently unsigned;
-where necessary, signedness is determined by the rtl operation
-instead.
+This represents either a floating-point constant of mode @var{m} or
+(on ports older ports that do not define
+@code{TARGET_SUPPORTS_WIDE_INT}) an integer constant too large to fit
+into @code{HOST_BITS_PER_WIDE_INT} bits but small enough to fit within
+twice that number of bits (GCC does not provide a mechanism to
+represent even larger constants).  In the latter case, @var{m} will be
+@code{VOIDmode}.  For integral values constants for modes with more
+bits than twice the number in @code{HOST_WIDE_INT} the implied high
+order bits of that constant are copies of the top bit of
+@code{CONST_DOUBLE_HIGH}.  Note however that integral values are
+neither inherently signed nor inherently unsigned; where necessary,
+signedness is determined by the rtl operation instead.
+
+On more modern ports, @code{CONST_DOUBLE} only represents floating
+point values.  New ports define to @code{TARGET_SUPPORTS_WIDE_INT} to
+make this designation.
 
 @findex CONST_DOUBLE_LOW
 If @var{m} is @code{VOIDmode}, the bits of the value are stored in
@@ -1558,6 +1563,37 @@ machine's or host machine's floating point format.  To convert them to
 the precise bit pattern used by the target machine, use the macro
 @code{REAL_VALUE_TO_TARGET_DOUBLE} and friends (@pxref{Data Output}).
 
+@findex CONST_WIDE_INT
+@item (const_wide_int:@var{m} @var{nunits} @var{elt0} @dots{})
+This contains an array of @code{HOST_WIDE_INTS} that is large enough
+to hold any constant that can be represented on the target.  This form
+of rtl is only used on targets that define
+@code{TARGET_SUPPORTS_WIDE_INT} to be non zero and then
+@code{CONST_DOUBLES} are only used to hold floating point values.  If
+the target leaves @code{TARGET_SUPPORTS_WIDE_INT} defined as 0,
+@code{CONST_WIDE_INT}s are not used and @code{CONST_DOUBLE}s are as
+they were before.
+
+The values are stored in a compressed format.   The higher order
+0s or -1s are not represented if they are just the logical sign
+extension of the number that is represented.   
+
+@findex CONST_WIDE_INT_VEC
+@item CONST_WIDE_INT_VEC (@var{code})
+Returns the entire array of @code{HOST_WIDE_INT}s that are used to
+store the value.   This macro should be rarely used.
+
+@findex CONST_WIDE_INT_NUNITS
+@item CONST_WIDE_INT_NUNITS (@var{code})
+The number of @code{HOST_WIDE_INT}s used to represent the number.
+Note that this generally be smaller than the number of
+@code{HOST_WIDE_INT}s implied by the mode size.
+
+@findex CONST_WIDE_INT_ELT
+@item CONST_WIDE_INT_NUNITS (@var{code},@var{i})
+Returns the @code{i}th element of the array.   Element 0 is contains
+the low order bits of the constant.
+
 @findex const_fixed
 @item (const_fixed:@var{m} @dots{})
 Represents a fixed-point constant of mode @var{m}.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index ef47b14..dc91857 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11336,3 +11336,48 @@ memory model bits are allowed.
 @deftypevr {Target Hook} {unsigned char} TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
 This value should be set if the result written by @code{atomic_test_and_set} is not exactly 1, i.e. the @code{bool} @code{true}.
 @end deftypevr
+@defmac TARGET_SUPPORTS_WIDE_INT
+
+On older ports, large integers are stored in @code{CONST_DOUBLE} rtl
+objects.  Newer ports define @code{TARGET_SUPPORTS_WIDE_INT} to be non
+zero to indicate that large integers are stored in
+@code{CONST_WIDE_INT} rtl objects.  The @code{CONST_WIDE_INT} allows
+very large integer constants to be represented.  @code{CONST_DOUBLE}
+are limited to twice the size of host's @code{HOST_WIDE_INT}
+representation.
+
+Converting a port mostly requires looking for the places where
+@code{CONST_DOUBLES} are used with @code{VOIDmode} and replacing that
+code with code that accesses @code{CONST_WIDE_INT}s.  @code{"grep -i
+const_double"} at the port level gets you to 95% of the changes that
+need to be made.  There are a few places that require a deeper look.
+
+@itemize @bullet
+@item
+There is no equivalent to @code{hval} and @code{lval} for
+@code{CONST_WIDE_INT}s.  This would be difficult to express in the md
+language since there are a variable number of elements.
+
+Most ports only check that @code{hval} is either 0 or -1 to see if the
+value is small.  As mentioned above, this will no longer be necessary
+since small constants are always @code{CONST_INT}.  Of course there
+are still a few exceptions, the alpha's constraint used by the zap
+instruction certainly requires careful examination by C code.
+However, all the current code does is pass the hval and lval to C
+code, so evolving the c code to look at the @code{CONST_WIDE_INT} is
+not really a large change.
+
+@item
+Because there is no standard template that ports use to materialize
+constants, there is likely to be some futzing that is unique to each
+port in this code.
+
+@item
+The rtx costs may have to be adjusted to properly account for larger
+constants that are represented as @code{CONST_WIDE_INT}.
+@end itemize
+
+All and all it does not takes long to convert ports that the
+maintainer is familiar with.
+
+@end defmac
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index f3945a4..acadd1e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -11172,3 +11172,48 @@ memory model bits are allowed.
 @end deftypefn
 
 @hook TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
+@defmac TARGET_SUPPORTS_WIDE_INT
+
+On older ports, large integers are stored in @code{CONST_DOUBLE} rtl
+objects.  Newer ports define @code{TARGET_SUPPORTS_WIDE_INT} to be non
+zero to indicate that large integers are stored in
+@code{CONST_WIDE_INT} rtl objects.  The @code{CONST_WIDE_INT} allows
+very large integer constants to be represented.  @code{CONST_DOUBLE}
+are limited to twice the size of host's @code{HOST_WIDE_INT}
+representation.
+
+Converting a port mostly requires looking for the places where
+@code{CONST_DOUBLES} are used with @code{VOIDmode} and replacing that
+code with code that accesses @code{CONST_WIDE_INT}s.  @samp{"grep -i
+const_double"} at the port level gets you to 95% of the changes that
+need to be made.  There are a few places that require a deeper look.
+
+@itemize @bullet
+@item
+There is no equivalent to @code{hval} and @code{lval} for
+@code{CONST_WIDE_INT}s.  This would be difficult to express in the md
+language since there are a variable number of elements.
+
+Most ports only check that @code{hval} is either 0 or -1 to see if the
+value is small.  As mentioned above, this will no longer be necessary
+since small constants are always @code{CONST_INT}.  Of course there
+are still a few exceptions, the alpha's constraint used by the zap
+instruction certainly requires careful examination by C code.
+However, all the current code does is pass the hval and lval to C
+code, so evolving the c code to look at the @code{CONST_WIDE_INT} is
+not really a large change.
+
+@item
+Because there is no standard template that ports use to materialize
+constants, there is likely to be some futzing that is unique to each
+port in this code.
+
+@item
+The rtx costs may have to be adjusted to properly account for larger
+constants that are represented as @code{CONST_WIDE_INT}.
+@end itemize
+
+All and all it does not takes long to convert ports that the
+maintainer is familiar with.
+
+@end defmac
diff --git a/gcc/dojump.c b/gcc/dojump.c
index 35cb2cf..d12bb67 100644
--- a/gcc/dojump.c
+++ b/gcc/dojump.c
@@ -144,6 +144,7 @@ static bool
 prefer_and_bit_test (enum machine_mode mode, int bitnum)
 {
   bool speed_p;
+  wide_int mask = wide_int::set_bit_in_zero (bitnum, mode);
 
   if (and_test == 0)
     {
@@ -164,8 +165,7 @@ prefer_and_bit_test (enum machine_mode mode, int bitnum)
     }
 
   /* Fill in the integers.  */
-  XEXP (and_test, 1)
-    = immed_double_int_const (double_int_zero.set_bit (bitnum), mode);
+  XEXP (and_test, 1) = immed_wide_int_const (mask, mode);
   XEXP (XEXP (shift_test, 0), 1) = GEN_INT (bitnum);
 
   speed_p = optimize_insn_for_speed_p ();
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index f0256ae..42765a6 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -325,6 +325,17 @@ 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)
 {
@@ -1356,6 +1367,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;
@@ -1612,6 +1626,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 ();
 	  }
@@ -1789,6 +1807,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);
@@ -1998,6 +2030,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 ();
 	  }
@@ -3096,7 +3143,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 *);
 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,
@@ -3721,6 +3768,20 @@ AT_unsigned (dw_attr_ref a)
 /* Add an unsigned double integer attribute value to a DIE.  */
 
 static inline void
+add_AT_wide (dw_die_ref die, enum dwarf_attribute attr_kind,
+	     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 = w;
+  add_dwarf_attr (die, &attr);
+}
+
+/* Add an unsigned double integer attribute value to a DIE.  */
+
+static inline void
 add_AT_double (dw_die_ref die, enum dwarf_attribute attr_kind,
 	       HOST_WIDE_INT high, unsigned HOST_WIDE_INT low)
 {
@@ -5274,6 +5335,19 @@ 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;
@@ -5429,6 +5503,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 (at->dw_attr_val.v.val_vec);
       break;
@@ -5699,6 +5776,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 (sizeof (at->dw_attr_val.v.val_vec));
@@ -6163,6 +6246,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)
@@ -7625,6 +7710,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)
@@ -7961,6 +8053,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))
@@ -8400,6 +8506,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;
@@ -11511,9 +11643,8 @@ 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 
+      (wide_int::set_bit_in_zero (GET_MODE_PRECISION (mode) - 1, 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
@@ -12440,7 +12571,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
@@ -12452,13 +12592,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
+	    = wide_int::from_rtx (rtl, mode);
 	}
       break;
 
@@ -12929,7 +13082,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
@@ -12941,12 +13102,26 @@ 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))
+	{
+	  gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
+
+	  /* Note that a CONST_DOUBLE rtx could represent either an integer
+	     or a floating-point constant.  A CONST_DOUBLE is used whenever
+	     the constant requires more than one word in order to be
+	     adequately represented.  We output CONST_DOUBLEs as blocks.  */
+	  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
+	    = wide_int::from_rtx (rtl, mode);
 	}
       break;
 
@@ -12962,6 +13137,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))
@@ -12970,15 +13146,8 @@ 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);
-		    }
+		  wide_int val = wide_int::from_rtx (elt, imode);
+		  insert_wide_int (val, p);
 		}
 	      break;
 
@@ -14603,22 +14772,27 @@ 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)
 {
-  unsigned char *p0 = dest;
-  unsigned char *p1 = dest + sizeof (HOST_WIDE_INT);
+  int i;
 
   if (WORDS_BIG_ENDIAN)
-    {
-      p0 = p1;
-      p1 = dest;
-    }
-
-  insert_int ((HOST_WIDE_INT) val.low, sizeof (HOST_WIDE_INT), p0);
-  insert_int ((HOST_WIDE_INT) val.high, sizeof (HOST_WIDE_INT), p1);
+    for (i = (int)get_full_len (val) - 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 < (int)get_full_len (val); 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.  */
@@ -14663,6 +14837,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,
+		   wide_int::from_rtx (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
@@ -14671,7 +14850,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);
@@ -14679,9 +14861,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;
 
@@ -14694,6 +14873,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))
 	  {
@@ -14701,15 +14881,8 @@ 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);
-		  }
+		wide_int val = wide_int::from_rtx (elt, imode);
+		insert_wide_int (val, p);
 	      }
 	    break;
 
@@ -22753,6 +22926,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;
@@ -22842,6 +23018,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 ();
 	  }
@@ -22990,6 +23169,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:
@@ -23033,6 +23214,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 ();
 	}
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index 8027c1e..efd4379 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_DWARF2OUT_H 1
 
 #include "dwarf2.h"	/* ??? Remove this once only used by dwarf2foo.c.  */
+#include "wide-int.h"
 
 typedef struct die_struct *dw_die_ref;
 typedef const struct die_struct *const_dw_die_ref;
@@ -140,6 +141,7 @@ enum dw_val_class
   dw_val_class_const,
   dw_val_class_unsigned_const,
   dw_val_class_const_double,
+  dw_val_class_wide_int,
   dw_val_class_vec,
   dw_val_class_flag,
   dw_val_class_die_ref,
@@ -181,6 +183,7 @@ typedef struct GTY(()) dw_val_struct {
       HOST_WIDE_INT GTY ((default)) val_int;
       unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
       double_int GTY ((tag ("dw_val_class_const_double"))) val_double;
+      wide_int GTY ((tag ("dw_val_class_wide_int"))) val_wide;
       dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
       struct dw_val_die_union
 	{
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index a15be51..af80310 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -124,6 +124,9 @@ rtx cc0_rtx;
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
      htab_t const_int_htab;
 
+static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
+     htab_t const_wide_int_htab;
+
 /* A hash table storing memory attribute structures.  */
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct mem_attrs)))
      htab_t mem_attrs_htab;
@@ -149,6 +152,11 @@ static void set_used_decls (tree);
 static void mark_label_nuses (rtx);
 static hashval_t const_int_htab_hash (const void *);
 static int const_int_htab_eq (const void *, const void *);
+#if TARGET_SUPPORTS_WIDE_INT
+static hashval_t const_wide_int_htab_hash (const void *);
+static int const_wide_int_htab_eq (const void *, const void *);
+static rtx lookup_const_wide_int (rtx);
+#endif
 static hashval_t const_double_htab_hash (const void *);
 static int const_double_htab_eq (const void *, const void *);
 static rtx lookup_const_double (rtx);
@@ -185,6 +193,43 @@ const_int_htab_eq (const void *x, const void *y)
   return (INTVAL ((const_rtx) x) == *((const HOST_WIDE_INT *) y));
 }
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns a hash code for X (which is a really a CONST_WIDE_INT).  */
+
+static hashval_t
+const_wide_int_htab_hash (const void *x)
+{
+  int i;
+  HOST_WIDE_INT hash = 0;
+  const_rtx xr = (const_rtx) x;
+
+  for (i = 0; i < CONST_WIDE_INT_NUNITS (xr); i++)
+    hash += CONST_WIDE_INT_ELT (xr, i);
+
+  return (hashval_t) hash;
+}
+
+/* Returns nonzero if the value represented by X (which is really a
+   CONST_WIDE_INT) is the same as that given by Y (which is really a
+   CONST_WIDE_INT).  */
+
+static int
+const_wide_int_htab_eq (const void *x, const void *y)
+{
+  int i;
+  const_rtx xr = (const_rtx)x;
+  const_rtx yr = (const_rtx)y;
+  if (CONST_WIDE_INT_NUNITS (xr) != CONST_WIDE_INT_NUNITS (yr))
+    return 0;
+
+  for (i = 0; i < CONST_WIDE_INT_NUNITS (xr); i++)
+    if (CONST_WIDE_INT_ELT (xr, i) != CONST_WIDE_INT_ELT (yr, i))
+      return 0;
+  
+  return 1;
+}
+#endif
+
 /* Returns a hash code for X (which is really a CONST_DOUBLE).  */
 static hashval_t
 const_double_htab_hash (const void *x)
@@ -192,7 +237,7 @@ const_double_htab_hash (const void *x)
   const_rtx const value = (const_rtx) x;
   hashval_t h;
 
-  if (GET_MODE (value) == VOIDmode)
+  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (value) == VOIDmode)
     h = CONST_DOUBLE_LOW (value) ^ CONST_DOUBLE_HIGH (value);
   else
     {
@@ -212,7 +257,7 @@ const_double_htab_eq (const void *x, const void *y)
 
   if (GET_MODE (a) != GET_MODE (b))
     return 0;
-  if (GET_MODE (a) == VOIDmode)
+  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (a) == VOIDmode)
     return (CONST_DOUBLE_LOW (a) == CONST_DOUBLE_LOW (b)
 	    && CONST_DOUBLE_HIGH (a) == CONST_DOUBLE_HIGH (b));
   else
@@ -478,6 +523,7 @@ const_fixed_from_fixed_value (FIXED_VALUE_TYPE value, enum machine_mode mode)
   return lookup_const_fixed (fixed);
 }
 
+#if TARGET_SUPPORTS_WIDE_INT == 0
 /* Constructs double_int from rtx CST.  */
 
 double_int
@@ -497,17 +543,61 @@ rtx_to_double_int (const_rtx cst)
   
   return r;
 }
+#endif
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Determine whether WIDE_INT, already exists in the hash table.  If
+   so, return its counterpart; otherwise add it to the hash table and
+   return it.  */
+
+static rtx
+lookup_const_wide_int (rtx wint)
+{
+  void **slot = htab_find_slot (const_wide_int_htab, wint, INSERT);
+  if (*slot == 0)
+    *slot = wint;
 
-/* Return a CONST_DOUBLE or CONST_INT for a value specified as
-   a double_int.  */
+  return (rtx) *slot;
+}
+#endif
 
+/* V contains a wide_int.  A CONST_INT or CONST_WIDE_INT (if
+   TARGET_SUPPORTS_WIDE_INT is defined) or CONST_DOUBLE if
+   TARGET_SUPPORTS_WIDE_INT is not defined is produced based on the
+   number of HOST_WIDE_INTs that are necessary to represent the value
+   in compact form.  */
 rtx
-immed_double_int_const (double_int i, enum machine_mode mode)
+immed_wide_int_const (const wide_int &v, enum machine_mode mode)
 {
-  return immed_double_const (i.low, i.high, mode);
+  unsigned int len = v.get_len ();
+
+  if (len < 2)
+    return gen_int_mode (v.elt (0), mode);
+
+  gcc_assert (GET_MODE_PRECISION (mode) == v.get_precision ());
+  gcc_assert (GET_MODE_BITSIZE (mode) == v.get_bitsize ());
+
+#if TARGET_SUPPORTS_WIDE_INT
+  {
+    rtx value = const_wide_int_alloc (len);
+    unsigned int i;
+
+    /* It is so tempting to just put the mode in here.  Must control
+       myself ... */
+    PUT_MODE (value, VOIDmode);
+    HWI_PUT_NUM_ELEM (CONST_WIDE_INT_VEC (value), len);
+
+    for (i = 0; i < len; i++)
+      CONST_WIDE_INT_ELT (value, i) = v.elt (i);
+
+    return lookup_const_wide_int (value);
+  }
+#else
+  return immed_double_const (v.elt (0), v.elt (1), mode);
+#endif
 }
 
+#if TARGET_SUPPORTS_WIDE_INT == 0
 /* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair
    of ints: I0 is the low-order word and I1 is the high-order word.
    For values that are larger than HOST_BITS_PER_DOUBLE_INT, the
@@ -559,6 +649,7 @@ immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode)
 
   return lookup_const_double (value);
 }
+#endif
 
 rtx
 gen_rtx_REG (enum machine_mode mode, unsigned int regno)
@@ -5609,11 +5700,15 @@ init_emit_once (void)
   enum machine_mode mode;
   enum machine_mode double_mode;
 
-  /* Initialize the CONST_INT, CONST_DOUBLE, CONST_FIXED, and memory attribute
-     hash tables.  */
+  /* Initialize the CONST_INT, CONST_WIDE_INT, CONST_DOUBLE,
+     CONST_FIXED, and memory attribute hash tables.  */
   const_int_htab = htab_create_ggc (37, const_int_htab_hash,
 				    const_int_htab_eq, NULL);
 
+#if TARGET_SUPPORTS_WIDE_INT
+  const_wide_int_htab = htab_create_ggc (37, const_wide_int_htab_hash,
+					 const_wide_int_htab_eq, NULL);
+#endif
   const_double_htab = htab_create_ggc (37, const_double_htab_hash,
 				       const_double_htab_eq, NULL);
 
diff --git a/gcc/explow.c b/gcc/explow.c
index 6109832..3efda04 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -97,38 +97,9 @@ plus_constant (enum machine_mode mode, rtx x, HOST_WIDE_INT c)
 
   switch (code)
     {
-    case CONST_INT:
-      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
-	{
-	  double_int di_x = double_int::from_shwi (INTVAL (x));
-	  double_int di_c = double_int::from_shwi (c);
-
-	  bool overflow;
-	  double_int v = di_x.add_with_sign (di_c, false, &overflow);
-	  if (overflow)
-	    gcc_unreachable ();
-
-	  return immed_double_int_const (v, VOIDmode);
-	}
-
-      return GEN_INT (INTVAL (x) + c);
-
-    case CONST_DOUBLE:
-      {
-	double_int di_x = double_int::from_pair (CONST_DOUBLE_HIGH (x),
-						 CONST_DOUBLE_LOW (x));
-	double_int di_c = double_int::from_shwi (c);
-
-	bool overflow;
-	double_int v = di_x.add_with_sign (di_c, false, &overflow);
-	if (overflow)
-	  /* Sorry, we have no way to represent overflows this wide.
-	     To fix, add constant support wider than CONST_DOUBLE.  */
-	  gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT);
-
-	return immed_double_int_const (v, VOIDmode);
-      }
-
+    CASE_CONST_SCALAR_INT:
+      return immed_wide_int_const (wide_int::from_rtx (x, mode) 
+				   + wide_int::from_shwi (c, mode), mode);
     case MEM:
       /* If this is a reference to the constant pool, try replacing it with
 	 a reference to a new constant.  If the resulting address isn't
diff --git a/gcc/expmed.c b/gcc/expmed.c
index fc29ac4..198c83d 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -58,7 +58,6 @@ static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
 static rtx extract_fixed_bit_field (enum machine_mode, rtx,
 				    unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT, rtx, int, bool);
-static rtx mask_rtx (enum machine_mode, int, int, int);
 static rtx lshift_value (enum machine_mode, rtx, int, int);
 static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT, int);
@@ -66,6 +65,18 @@ static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
 static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 
+/* Return a constant integer mask value of mode MODE with BITSIZE ones
+   followed by BITPOS zeros, or the complement of that if COMPLEMENT.
+   The mask is truncated if necessary to the width of mode MODE.  The
+   mask is zero-extended if BITSIZE+BITPOS is too small for MODE.  */
+
+static inline rtx 
+mask_rtx (enum machine_mode mode, int bitpos, int bitsize, bool complement)
+{
+  return immed_wide_int_const 
+    (wide_int::shifted_mask (bitpos, bitsize, complement, mode), mode);
+}
+
 /* Test whether a value is zero of a power of two.  */
 #define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
 
@@ -1825,39 +1836,16 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
   return expand_shift (RSHIFT_EXPR, mode, op0,
 		       GET_MODE_BITSIZE (mode) - bitsize, target, 0);
 }
-\f
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) mask value
-   of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
-   complement of that if COMPLEMENT.  The mask is truncated if
-   necessary to the width of mode MODE.  The mask is zero-extended if
-   BITSIZE+BITPOS is too small for MODE.  */
-
-static rtx
-mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
-{
-  double_int mask;
-
-  mask = double_int::mask (bitsize);
-  mask = mask.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
-  if (complement)
-    mask = ~mask;
-
-  return immed_double_int_const (mask, mode);
-}
-
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
-   VALUE truncated to BITSIZE bits and then shifted left BITPOS bits.  */
+/* Return a constant integer rtx with the value VALUE truncated to
+   BITSIZE bits and then shifted left BITPOS bits.  */
 
 static rtx
 lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
 {
-  double_int val;
-  
-  val = double_int::from_uhwi (INTVAL (value)).zext (bitsize);
-  val = val.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
-  return immed_double_int_const (val, mode);
+  return 
+    immed_wide_int_const (wide_int::from_rtx (value, mode)
+			  .zext (bitsize)
+			  .lshift (bitpos, wide_int::NONE), mode);
 }
 \f
 /* Extract a bit field that is split across two words
@@ -3062,34 +3050,41 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 	 only if the constant value exactly fits in an `unsigned int' without
 	 any truncation.  This means that multiplying by negative values does
 	 not work; results are off by 2^32 on a 32 bit machine.  */
-
       if (CONST_INT_P (scalar_op1))
 	{
 	  coeff = INTVAL (scalar_op1);
 	  is_neg = coeff < 0;
 	}
+#if TARGET_SUPPORTS_WIDE_INT
+      else if (CONST_WIDE_INT_P (scalar_op1))
+#else
       else if (CONST_DOUBLE_AS_INT_P (scalar_op1))
+#endif
 	{
-	  /* If we are multiplying in DImode, it may still be a win
-	     to try to work with shifts and adds.  */
-	  if (CONST_DOUBLE_HIGH (scalar_op1) == 0
-	      && CONST_DOUBLE_LOW (scalar_op1) > 0)
+	  int p = GET_MODE_PRECISION (mode);
+	  wide_int val = wide_int::from_rtx (scalar_op1, mode);
+	  int shift = val.exact_log2 (); 
+	  /* Perfect power of 2.  */
+	  is_neg = false;
+	  if (shift > 0)
 	    {
-	      coeff = CONST_DOUBLE_LOW (scalar_op1);
-	      is_neg = false;
+	      /* Do the shift count trucation against the bitsize, not
+		 the precision.  See the comment above
+		 wide-int.c:trunc_shift for details.  */
+	      if (SHIFT_COUNT_TRUNCATED)
+		shift &= GET_MODE_BITSIZE (mode) - 1;
+	      /* We could consider adding just a move of 0 to target
+		 if the shift >= p  */
+	      if (shift < p)
+		return expand_shift (LSHIFT_EXPR, mode, op0, 
+				     shift, target, unsignedp);
+	      /* Any positive number that fits in a word.  */
+	      coeff = CONST_WIDE_INT_ELT (scalar_op1, 0);
 	    }
-	  else if (CONST_DOUBLE_LOW (scalar_op1) == 0)
+	  else if (val.sign_mask () == 0)
 	    {
-	      coeff = CONST_DOUBLE_HIGH (scalar_op1);
-	      if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
-		{
-		  int shift = floor_log2 (coeff) + HOST_BITS_PER_WIDE_INT;
-		  if (shift < HOST_BITS_PER_DOUBLE_INT - 1
-		      || mode_bitsize <= HOST_BITS_PER_DOUBLE_INT)
-		    return expand_shift (LSHIFT_EXPR, mode, op0,
-					 shift, target, unsignedp);
-		}
-	      goto skip_synth;
+	      /* Any positive number that fits in a word.  */
+	      coeff = CONST_WIDE_INT_ELT (scalar_op1, 0);
 	    }
 	  else
 	    goto skip_synth;
@@ -3579,9 +3574,10 @@ expmed_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
 static rtx
 expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 {
-  unsigned HOST_WIDE_INT masklow, maskhigh;
   rtx result, temp, shift, label;
   int logd;
+  wide_int mask;
+  int prec = GET_MODE_PRECISION (mode);
 
   logd = floor_log2 (d);
   result = gen_reg_rtx (mode);
@@ -3594,8 +3590,8 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 				      mode, 0, -1);
       if (signmask)
 	{
+	  HOST_WIDE_INT masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
 	  signmask = force_reg (mode, signmask);
-	  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
 	  shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
 
 	  /* Use the rtx_cost of a LSHIFTRT instruction to determine
@@ -3640,19 +3636,11 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
      modulus.  By including the signbit in the operation, many targets
      can avoid an explicit compare operation in the following comparison
      against zero.  */
-
-  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
-  if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
-    {
-      masklow |= (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1);
-      maskhigh = -1;
-    }
-  else
-    maskhigh = (HOST_WIDE_INT) -1
-		 << (GET_MODE_BITSIZE (mode) - HOST_BITS_PER_WIDE_INT - 1);
+  mask = wide_int::mask (logd, false, mode);
+  mask = mask.set_bit (prec - 1);
 
   temp = expand_binop (mode, and_optab, op0,
-		       immed_double_const (masklow, maskhigh, mode),
+		       immed_wide_int_const (mask, mode),
 		       result, 1, OPTAB_LIB_WIDEN);
   if (temp != result)
     emit_move_insn (result, temp);
@@ -3662,10 +3650,10 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 
   temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
 		       0, OPTAB_LIB_WIDEN);
-  masklow = (HOST_WIDE_INT) -1 << logd;
-  maskhigh = -1;
+
+  mask = wide_int::mask (logd, true, mode); 
   temp = expand_binop (mode, ior_optab, temp,
-		       immed_double_const (masklow, maskhigh, mode),
+		       immed_wide_int_const (mask, mode),
 		       result, 1, OPTAB_LIB_WIDEN);
   temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
 		       0, OPTAB_LIB_WIDEN);
@@ -4919,8 +4907,12 @@ make_tree (tree type, rtx x)
 	return t;
       }
 
+    case CONST_WIDE_INT:
+      t = wide_int_to_tree (type, wide_int::from_rtx (x, TYPE_MODE (type)));
+      return t;
+
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	t = build_int_cst_wide (type,
 				CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
       else
diff --git a/gcc/expr.c b/gcc/expr.c
index 48e2581..f570552 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -712,23 +712,23 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
   if (mode == oldmode)
     return x;
 
-  /* There is one case that we must handle specially: If we are converting
-     a CONST_INT into a mode whose size is twice HOST_BITS_PER_WIDE_INT and
-     we are to interpret the constant as unsigned, gen_lowpart will do
-     the wrong if the constant appears negative.  What we want to do is
-     make the high-order word of the constant zero, not all ones.  */
+  /* There is one case that we must handle specially: If we are
+     converting a CONST_INT into a mode whose size is larger than
+     HOST_BITS_PER_WIDE_INT and we are to interpret the constant as
+     unsigned, gen_lowpart will do the wrong if the constant appears
+     negative.  What we want to do is make the high-order word of the
+     constant zero, not all ones.  */
 
   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
-      && GET_MODE_BITSIZE (mode) == HOST_BITS_PER_DOUBLE_INT
+      && GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT
       && CONST_INT_P (x) && INTVAL (x) < 0)
     {
-      double_int val = double_int::from_uhwi (INTVAL (x));
-
+      HOST_WIDE_INT val = INTVAL (x);
       /* We need to zero extend VAL.  */
       if (oldmode != VOIDmode)
-	val = val.zext (GET_MODE_BITSIZE (oldmode));
+	val &= GET_MODE_PRECISION (oldmode) - 1;
 
-      return immed_double_int_const (val, mode);
+      return immed_wide_int_const (wide_int::from_uhwi (val, mode), mode);
     }
 
   /* We can do this with a gen_lowpart if both desired and current modes
@@ -740,7 +740,11 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
        && GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT)
       || (GET_MODE_CLASS (mode) == MODE_INT
 	  && GET_MODE_CLASS (oldmode) == MODE_INT
-	  && (CONST_DOUBLE_AS_INT_P (x) 
+#if TARGET_SUPPORTS_WIDE_INT
+	  && (CONST_WIDE_INT_P (x)
+#else
+ 	  && (CONST_DOUBLE_AS_INT_P (x)
+#endif
 	      || (GET_MODE_PRECISION (mode) <= GET_MODE_PRECISION (oldmode)
 		  && ((MEM_P (x) && ! MEM_VOLATILE_P (x)
 		       && direct_load[(int) mode])
@@ -1745,6 +1749,7 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
 	    {
 	      rtx first, second;
 
+	      /* TODO: const_wide_int can have sizes other than this...  */
 	      gcc_assert (2 * len == ssize);
 	      split_double (src, &first, &second);
 	      if (i)
@@ -5192,10 +5197,10 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 			       &alt_rtl);
     }
 
-  /* If TEMP is a VOIDmode constant and the mode of the type of EXP is not
-     the same as that of TARGET, adjust the constant.  This is needed, for
-     example, in case it is a CONST_DOUBLE and we want only a word-sized
-     value.  */
+  /* If TEMP is a VOIDmode constant and the mode of the type of EXP is
+     not the same as that of TARGET, adjust the constant.  This is
+     needed, for example, in case it is a CONST_DOUBLE or
+     CONST_WIDE_INT and we want only a word-sized value.  */
   if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode
       && TREE_CODE (exp) != ERROR_MARK
       && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
@@ -7694,11 +7699,12 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
 
   /* All elts simple constants => refer to a constant in memory.  But
      if this is a non-BLKmode mode, let it store a field at a time
-     since that should make a CONST_INT or CONST_DOUBLE when we
-     fold.  Likewise, if we have a target we can use, it is best to
-     store directly into the target unless the type is large enough
-     that memcpy will be used.  If we are making an initializer and
-     all operands are constant, put it in memory as well.
+     since that should make a CONST_INT, CONST_WIDE_INT or
+     CONST_DOUBLE when we fold.  Likewise, if we have a target we can
+     use, it is best to store directly into the target unless the type
+     is large enough that memcpy will be used.  If we are making an
+     initializer and all operands are constant, put it in memory as
+     well.
 
      FIXME: Avoid trying to fill vector constructors piece-meal.
      Output them with output_constant_def below unless we're sure
@@ -8167,17 +8173,18 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 	      && TREE_CONSTANT (treeop1))
 	    {
 	      rtx constant_part;
+	      HOST_WIDE_INT wc;
+	      enum machine_mode wmode = TYPE_MODE (TREE_TYPE (treeop1));
 
 	      op1 = expand_expr (treeop1, subtarget, VOIDmode,
 				 EXPAND_SUM);
-	      /* Use immed_double_const to ensure that the constant is
+	      /* Use wide_int::from_shwi to ensure that the constant is
 		 truncated according to the mode of OP1, then sign extended
 		 to a HOST_WIDE_INT.  Using the constant directly can result
 		 in non-canonical RTL in a 64x32 cross compile.  */
-	      constant_part
-		= immed_double_const (TREE_INT_CST_LOW (treeop0),
-				      (HOST_WIDE_INT) 0,
-				      TYPE_MODE (TREE_TYPE (treeop1)));
+	      wc = TREE_INT_CST_LOW (treeop0);
+	      constant_part 
+		= immed_wide_int_const (wide_int::from_shwi (wc, wmode), wmode);
 	      op1 = plus_constant (mode, op1, INTVAL (constant_part));
 	      if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
 		op1 = force_operand (op1, target);
@@ -8189,7 +8196,8 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 		   && TREE_CONSTANT (treeop0))
 	    {
 	      rtx constant_part;
-
+	      HOST_WIDE_INT wc;
+	      enum machine_mode wmode = TYPE_MODE (TREE_TYPE (treeop0));
 	      op0 = expand_expr (treeop0, subtarget, VOIDmode,
 				 (modifier == EXPAND_INITIALIZER
 				 ? EXPAND_INITIALIZER : EXPAND_SUM));
@@ -8203,14 +8211,13 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 		    return simplify_gen_binary (PLUS, mode, op0, op1);
 		  goto binop2;
 		}
-	      /* Use immed_double_const to ensure that the constant is
+	      /* Use wide_int::from_shwi to ensure that the constant is
 		 truncated according to the mode of OP1, then sign extended
 		 to a HOST_WIDE_INT.  Using the constant directly can result
 		 in non-canonical RTL in a 64x32 cross compile.  */
-	      constant_part
-		= immed_double_const (TREE_INT_CST_LOW (treeop1),
-				      (HOST_WIDE_INT) 0,
-				      TYPE_MODE (TREE_TYPE (treeop0)));
+	      wc = TREE_INT_CST_LOW (treeop1);
+	      constant_part 
+		= immed_wide_int_const (wide_int::from_shwi (wc, wmode), wmode);
 	      op0 = plus_constant (mode, op0, INTVAL (constant_part));
 	      if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
 		op0 = force_operand (op0, target);
@@ -8712,10 +8719,13 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 	 for unsigned bitfield expand this as XOR with a proper constant
 	 instead.  */
       if (reduce_bit_field && TYPE_UNSIGNED (type))
-	temp = expand_binop (mode, xor_optab, op0,
-			     immed_double_int_const
-			       (double_int::mask (TYPE_PRECISION (type)), mode),
-			     target, 1, OPTAB_LIB_WIDEN);
+	{
+	  wide_int mask = wide_int::mask (TYPE_PRECISION (type), false, mode);
+
+	  temp = expand_binop (mode, xor_optab, op0,
+			       immed_wide_int_const (mask, mode),
+			       target, 1, OPTAB_LIB_WIDEN);
+	}
       else
 	temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
       gcc_assert (temp);
@@ -9300,9 +9310,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return decl_rtl;
 
     case INTEGER_CST:
-      temp = immed_double_const (TREE_INT_CST_LOW (exp),
-				 TREE_INT_CST_HIGH (exp), mode);
-
+      temp = immed_wide_int_const (wide_int::from_tree (exp), 
+				   TYPE_MODE (TREE_TYPE (exp)));
       return temp;
 
     case VECTOR_CST:
@@ -9533,8 +9542,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 	op0 = memory_address_addr_space (address_mode, op0, as);
 	if (!integer_zerop (TREE_OPERAND (exp, 1)))
 	  {
-	    rtx off
-	      = immed_double_int_const (mem_ref_offset (exp), address_mode);
+	    wide_int wi = wide_int::from_double_int
+	      (mem_ref_offset (exp), address_mode);
+	    rtx off = immed_wide_int_const (wi, address_mode);
 	    op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
 	  }
 	op0 = memory_address_addr_space (mode, op0, as);
@@ -10411,9 +10421,10 @@ reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
     }
   else if (TYPE_UNSIGNED (type))
     {
-      rtx mask = immed_double_int_const (double_int::mask (prec),
-					 GET_MODE (exp));
-      return expand_and (GET_MODE (exp), exp, mask, target);
+      enum machine_mode mode = GET_MODE (exp);
+      rtx mask = immed_wide_int_const 
+	(wide_int::mask (prec, false, mode), mode);
+      return expand_and (mode, exp, mask, target);
     }
   else
     {
@@ -10985,8 +10996,9 @@ const_vector_from_tree (tree exp)
 	RTVEC_ELT (v, i) = CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (elt),
 							 inner);
       else
-	RTVEC_ELT (v, i) = immed_double_int_const (tree_to_double_int (elt),
-						   inner);
+	RTVEC_ELT (v, i) 
+	  = immed_wide_int_const (wide_int::from_tree (elt),
+				  TYPE_MODE (TREE_TYPE (elt)));
     }
 
   return gen_rtx_CONST_VECTOR (mode, v);
diff --git a/gcc/final.c b/gcc/final.c
index 2bd6aeb..0eb1a64 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -3728,8 +3728,16 @@ output_addr_const (FILE *file, rtx x)
       output_addr_const (file, XEXP (x, 0));
       break;
 
+    case CONST_WIDE_INT:
+      /* This should be ok for a while.  */
+      gcc_assert (CONST_WIDE_INT_NUNITS (x) == 2);
+      fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
+	       (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, 1),
+	       (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, 0));
+      break;
+
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
+      if (CONST_DOUBLE_AS_INT_P (x))
 	{
 	  /* We can use %d if the number is one word and positive.  */
 	  if (CONST_DOUBLE_HIGH (x))
diff --git a/gcc/genemit.c b/gcc/genemit.c
index eefe497..44ce2d2 100644
--- a/gcc/genemit.c
+++ b/gcc/genemit.c
@@ -205,6 +205,7 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used)
 
     case CONST_DOUBLE:
     case CONST_FIXED:
+    case CONST_WIDE_INT:
       /* These shouldn't be written in MD files.  Instead, the appropriate
 	 routines in varasm.c should be called.  */
       gcc_unreachable ();
diff --git a/gcc/gengenrtl.c b/gcc/gengenrtl.c
index 58d3142..7a89039 100644
--- a/gcc/gengenrtl.c
+++ b/gcc/gengenrtl.c
@@ -143,6 +143,7 @@ static int
 excluded_rtx (int idx)
 {
   return ((strcmp (defs[idx].enumname, "CONST_DOUBLE") == 0)
+	  || (strcmp (defs[idx].enumname, "CONST_WIDE_INT") == 0)
 	  || (strcmp (defs[idx].enumname, "CONST_FIXED") == 0));
 }
 
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index b3f73fe..06f7f5a 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -5548,6 +5548,7 @@ main (int argc, char **argv)
       POS_HERE (do_scalar_typedef ("REAL_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("FIXED_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("double_int", &pos));
+      POS_HERE (do_scalar_typedef ("wide_int", &pos));
       POS_HERE (do_scalar_typedef ("uint64_t", &pos));
       POS_HERE (do_scalar_typedef ("uint8", &pos));
       POS_HERE (do_scalar_typedef ("uintptr_t", &pos));
diff --git a/gcc/genpreds.c b/gcc/genpreds.c
index de91349..14fa326 100644
--- a/gcc/genpreds.c
+++ b/gcc/genpreds.c
@@ -613,7 +613,7 @@ write_one_predicate_function (struct pred_data *p)
   add_mode_tests (p);
 
   /* A normal predicate can legitimately not look at enum machine_mode
-     if it accepts only CONST_INTs and/or CONST_DOUBLEs.  */
+     if it accepts only CONST_INTs and/or CONST_WIDE_INT and/or CONST_DOUBLEs.  */
   printf ("int\n%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n{\n",
 	  p->name);
   write_predicate_stmts (p->exp);
@@ -810,8 +810,11 @@ add_constraint (const char *name, const char *regclass,
   if (is_const_int || is_const_dbl)
     {
       enum rtx_code appropriate_code
+#if TARGET_SUPPORTS_WIDE_INT
+	= is_const_int ? CONST_INT : CONST_WIDE_INT;
+#else
 	= is_const_int ? CONST_INT : CONST_DOUBLE;
-
+#endif
       /* Consider relaxing this requirement in the future.  */
       if (regclass
 	  || GET_CODE (exp) != AND
@@ -1075,12 +1078,17 @@ write_tm_constrs_h (void)
 	if (needs_ival)
 	  puts ("  if (CONST_INT_P (op))\n"
 		"    ival = INTVAL (op);");
+#if TARGET_SUPPORTS_WIDE_INT
+	if (needs_lval || needs_hval)
+	  error ("you can't use lval or hval");
+#else
 	if (needs_hval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)"
 		"    hval = CONST_DOUBLE_HIGH (op);");
 	if (needs_lval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)"
 		"    lval = CONST_DOUBLE_LOW (op);");
+#endif
 	if (needs_rval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode != VOIDmode)"
 		"    rval = CONST_DOUBLE_REAL_VALUE (op);");
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index 00290b0..9f44449 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -2776,7 +2776,13 @@ static const struct std_pred_table std_preds[] = {
   {"scratch_operand", false, false, {SCRATCH, REG}},
   {"immediate_operand", false, true, {UNKNOWN}},
   {"const_int_operand", false, false, {CONST_INT}},
+#if TARGET_SUPPORTS_WIDE_INT
+  {"const_wide_int_operand", false, false, {CONST_WIDE_INT}},
+  {"const_scalar_int_operand", false, false, {CONST_INT, CONST_WIDE_INT}},
+  {"const_double_operand", false, false, {CONST_DOUBLE}},
+#else
   {"const_double_operand", false, false, {CONST_INT, CONST_DOUBLE}},
+#endif
   {"nonimmediate_operand", false, false, {SUBREG, REG, MEM}},
   {"nonmemory_operand", false, true, {SUBREG, REG}},
   {"push_operand", false, false, {MEM}},
diff --git a/gcc/ggc-zone.c b/gcc/ggc-zone.c
index 2cf7167..500f736 100644
--- a/gcc/ggc-zone.c
+++ b/gcc/ggc-zone.c
@@ -1373,6 +1373,9 @@ ggc_alloc_typed_stat (enum gt_types_enum gte, size_t size
     case gt_ggc_e_9rtvec_def:
       return ggc_internal_alloc_zone_pass_stat (size, &rtl_zone);
 
+    case gt_ggc_e_10hwivec_def:
+      return ggc_internal_alloc_zone_pass_stat (size, &rtl_zone);
+
     default:
       return ggc_internal_alloc_zone_pass_stat (size, &main_zone);
     }
diff --git a/gcc/ggc.h b/gcc/ggc.h
index 37bbbd1..c8f3d00 100644
--- a/gcc/ggc.h
+++ b/gcc/ggc.h
@@ -271,6 +271,11 @@ extern struct alloc_zone tree_id_zone;
 			    + ((NELT) - 1) * sizeof (rtx),		\
 			    &rtl_zone)
 
+#define ggc_alloc_hwivec_sized(NELT)                                      \
+  ggc_alloc_zone_hwivec_def (sizeof (struct hwivec_def)			\
+			    + ((NELT) - 1) * sizeof (HOST_WIDE_INT),	\
+			    &rtl_zone)
+
 #if defined (GGC_ZONE) && !defined (GENERATOR_FILE)
 
 /* Allocate an object into the specified allocation zone.  */
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 353727f..d920fb0 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -838,7 +838,8 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
   if (CONSTANT_P (op1) || shift_mask >= BITS_PER_WORD)
     {
       carries = outof_input;
-      tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
+      tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD,
+						       op1_mode), op1_mode);
       tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
 				   0, true, methods);
     }
@@ -853,13 +854,14 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
 			      outof_input, const1_rtx, 0, unsignedp, methods);
       if (shift_mask == BITS_PER_WORD - 1)
 	{
-	  tmp = immed_double_const (-1, -1, op1_mode);
+	  tmp = immed_wide_int_const (wide_int::minus_one (op1_mode), op1_mode);
 	  tmp = simplify_expand_binop (op1_mode, xor_optab, op1, tmp,
 				       0, true, methods);
 	}
       else
 	{
-	  tmp = immed_double_const (BITS_PER_WORD - 1, 0, op1_mode);
+	  tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD - 1,
+							   op1_mode), op1_mode);
 	  tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
 				       0, true, methods);
 	}
@@ -1022,7 +1024,8 @@ expand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
      is true when the effective shift value is less than BITS_PER_WORD.
      Set SUPERWORD_OP1 to the shift count that should be used to shift
      OUTOF_INPUT into INTO_TARGET when the condition is false.  */
-  tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
+  tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD, op1_mode),
+			      op1_mode);
   if (!CONSTANT_P (op1) && shift_mask == BITS_PER_WORD - 1)
     {
       /* Set CMP1 to OP1 & BITS_PER_WORD.  The result is zero iff OP1
@@ -2872,7 +2875,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
   const struct real_format *fmt;
   int bitpos, word, nwords, i;
   enum machine_mode imode;
-  double_int mask;
+  wide_int mask;
   rtx temp, insns;
 
   /* The format has to have a simple sign bit.  */
@@ -2908,7 +2911,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
       nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
     }
 
-  mask = double_int_zero.set_bit (bitpos);
+  mask = wide_int::set_bit_in_zero (bitpos, imode);
   if (code == ABS)
     mask = ~mask;
 
@@ -2930,7 +2933,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
 	    {
 	      temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
 				   op0_piece,
-				   immed_double_int_const (mask, imode),
+				   immed_wide_int_const (mask, imode),
 				   targ_piece, 1, OPTAB_LIB_WIDEN);
 	      if (temp != targ_piece)
 		emit_move_insn (targ_piece, temp);
@@ -2948,7 +2951,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
     {
       temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
 			   gen_lowpart (imode, op0),
-			   immed_double_int_const (mask, imode),
+			   immed_wide_int_const (mask, imode),
 		           gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
       target = lowpart_subreg_maybe_copy (mode, temp, imode);
 
@@ -3547,7 +3550,7 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
     }
   else
     {
-      double_int mask;
+      wide_int mask;
 
       if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
 	{
@@ -3569,10 +3572,9 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 	  op1 = operand_subword_force (op1, word, mode);
 	}
 
-      mask = double_int_zero.set_bit (bitpos);
-
+      mask = wide_int::set_bit_in_zero (bitpos, imode);
       sign = expand_binop (imode, and_optab, op1,
-			   immed_double_int_const (mask, imode),
+			   immed_wide_int_const (mask, imode),
 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
 
@@ -3616,7 +3618,7 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 		     int bitpos, bool op0_is_abs)
 {
   enum machine_mode imode;
-  double_int mask;
+  wide_int mask, nmask;
   int word, nwords, i;
   rtx temp, insns;
 
@@ -3640,7 +3642,7 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
       nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
     }
 
-  mask = double_int_zero.set_bit (bitpos);
+  mask = wide_int::set_bit_in_zero (bitpos, imode);
 
   if (target == 0
       || target == op0
@@ -3660,14 +3662,16 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 	  if (i == word)
 	    {
 	      if (!op0_is_abs)
-		op0_piece
-		  = expand_binop (imode, and_optab, op0_piece,
-				  immed_double_int_const (~mask, imode),
-				  NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
+		{
+		  nmask = ~mask;
+  		  op0_piece
+		    = expand_binop (imode, and_optab, op0_piece,
+				    immed_wide_int_const (nmask, imode),
+				    NULL_RTX, 1, OPTAB_LIB_WIDEN);
+		}
 	      op1 = expand_binop (imode, and_optab,
 				  operand_subword_force (op1, i, mode),
-				  immed_double_int_const (mask, imode),
+				  immed_wide_int_const (mask, imode),
 				  NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
 	      temp = expand_binop (imode, ior_optab, op0_piece, op1,
@@ -3687,15 +3691,17 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
   else
     {
       op1 = expand_binop (imode, and_optab, gen_lowpart (imode, op1),
-		          immed_double_int_const (mask, imode),
+		          immed_wide_int_const (mask, imode),
 		          NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
       op0 = gen_lowpart (imode, op0);
       if (!op0_is_abs)
-	op0 = expand_binop (imode, and_optab, op0,
-			    immed_double_int_const (~mask, imode),
-			    NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
+	{
+	  nmask = ~mask;
+	  op0 = expand_binop (imode, and_optab, op0,
+			      immed_wide_int_const (nmask, imode),
+			      NULL_RTX, 1, OPTAB_LIB_WIDEN);
+	}
       temp = expand_binop (imode, ior_optab, op0, op1,
 			   gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
       target = lowpart_subreg_maybe_copy (mode, temp, imode);
diff --git a/gcc/postreload.c b/gcc/postreload.c
index 32c5b5f..54b1f27 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -297,27 +297,25 @@ reload_cse_simplify_set (rtx set, rtx insn)
 #ifdef LOAD_EXTEND_OP
 	  if (extend_op != UNKNOWN)
 	    {
-	      HOST_WIDE_INT this_val;
+	      wide_int result;
 
-	      /* ??? I'm lazy and don't wish to handle CONST_DOUBLE.  Other
-		 constants, such as SYMBOL_REF, cannot be extended.  */
-	      if (!CONST_INT_P (this_rtx))
+	      if (!CONST_SCALAR_INT_P (this_rtx))
 		continue;
 
-	      this_val = INTVAL (this_rtx);
 	      switch (extend_op)
 		{
 		case ZERO_EXTEND:
-		  this_val &= GET_MODE_MASK (GET_MODE (src));
+		  result = (wide_int::from_rtx (this_rtx, GET_MODE (src))
+			    .zext (word_mode));
 		  break;
 		case SIGN_EXTEND:
-		  /* ??? In theory we're already extended.  */
-		  if (this_val == trunc_int_for_mode (this_val, GET_MODE (src)))
-		    break;
+		  result = (wide_int::from_rtx (this_rtx, GET_MODE (src))
+			    .sext (word_mode));
+		  break;
 		default:
 		  gcc_unreachable ();
 		}
-	      this_rtx = GEN_INT (this_val);
+	      this_rtx = immed_wide_int_const (result, GET_MODE (src));
 	    }
 #endif
 	  this_cost = set_src_cost (this_rtx, speed);
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 75f9350..7a4f6f0 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -614,6 +614,12 @@ print_rtx (const_rtx in_rtx)
 	  fprintf (outfile, " [%s]", s);
 	}
       break;
+
+    case CONST_WIDE_INT:
+      if (! flag_simple)
+	fprintf (outfile, " ");
+      hwivec_output_hex (outfile, CONST_WIDE_INT_VEC (in_rtx));
+      break;
 #endif
 
     case CODE_LABEL:
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 7da12b5..5376688 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -808,6 +808,29 @@ validate_const_int (const char *string)
     fatal_with_file_and_line ("invalid decimal constant \"%s\"\n", string);
 }
 
+static void
+validate_const_wide_int (const char *string)
+{
+  const char *cp;
+  int valid = 1;
+
+  cp = string;
+  while (*cp && ISSPACE (*cp))
+    cp++;
+  /* Skip the leading 0x.  */
+  if (cp[0] == '0' || cp[1] == 'x')
+    cp += 2;
+  else
+    valid = 0;
+  if (*cp == 0)
+    valid = 0;
+  for (; *cp; cp++)
+    if (! ISXDIGIT (*cp))
+      valid = 0;
+  if (!valid)
+    fatal_with_file_and_line ("invalid hex constant \"%s\"\n", string);
+}
+
 /* Record that PTR uses iterator ITERATOR.  */
 
 static void
@@ -1321,6 +1344,56 @@ read_rtx_code (const char *code_name)
 	gcc_unreachable ();
       }
 
+  if (CONST_WIDE_INT_P (return_rtx))
+    {
+      read_name (&name);
+      validate_const_wide_int (name.string);
+      {
+	hwivec hwiv;
+	const char *s = name.string;
+	int len;
+	int index = 0;
+	int gs = HOST_BITS_PER_WIDE_INT/4;
+	int pos;
+	char * buf = XALLOCAVEC (char, gs + 1);
+	unsigned HOST_WIDE_INT wi;
+	int wlen;
+
+	/* Skip the leading spaces.  */
+	while (*s && ISSPACE (*s))
+	  s++;
+
+	/* Skip the leading 0x.  */
+	gcc_assert (s[0] == '0');
+	gcc_assert (s[1] == 'x');
+	s += 2;
+
+	len = strlen (s);
+	pos = len - gs;
+	wlen = (len + gs - 1) / gs;	/* Number of words needed */
+
+	return_rtx = const_wide_int_alloc (wlen);
+
+	hwiv = CONST_WIDE_INT_VEC (return_rtx);
+	while (pos > 0)
+	  {
+#if HOST_BITS_PER_WIDE_INT == 64
+	    sscanf (s + pos, "%16" HOST_WIDE_INT_PRINT "x", &wi);
+#else
+	    sscanf (s + pos, "%8" HOST_WIDE_INT_PRINT "x", &wi);
+#endif
+	    XHWIVEC_ELT (hwiv, index++) = wi;
+	    pos -= gs;
+	  }
+	strncpy (buf, s, gs - pos);
+	buf [gs - pos] = 0;
+	sscanf (buf, "%" HOST_WIDE_INT_PRINT "x", &wi);
+	XHWIVEC_ELT (hwiv, index++) = wi;
+	/* TODO: After reading, do we want to canonicalize with:
+	   value = lookup_const_wide_int (value); ? */
+      }
+    }
+
   c = read_skip_spaces ();
   /* Syntactic sugar for AND and IOR, allowing Lisp-like
      arbitrary number of arguments for them.  */
diff --git a/gcc/recog.c b/gcc/recog.c
index 3c56703..bbccb56 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -1143,7 +1143,7 @@ immediate_operand (rtx op, enum machine_mode mode)
 					    : mode, op));
 }
 
-/* Returns 1 if OP is an operand that is a CONST_INT.  */
+/* Returns 1 if OP is an operand that is a CONST_INT of mode MODE.  */
 
 int
 const_int_operand (rtx op, enum machine_mode mode)
@@ -1158,8 +1158,64 @@ const_int_operand (rtx op, enum machine_mode mode)
   return 1;
 }
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns 1 if OP is an operand that is a CONST_INT or CONST_WIDE_INT
+   of mode MODE.  */
+int
+const_scalar_int_operand (rtx op, enum machine_mode mode)
+{
+  if (!CONST_SCALAR_INT_P (op))
+    return 0;
+
+  if (CONST_INT_P (op))
+    return const_int_operand (op, mode);
+
+  if (mode != VOIDmode)
+    {
+      int prec = GET_MODE_PRECISION (mode);
+      int bitsize = GET_MODE_BITSIZE (mode);
+      
+      if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
+	return 0;
+      
+      if (prec == bitsize)
+	return 1;
+      else
+	{
+	  /* Multiword partial int.  */
+	  HOST_WIDE_INT x 
+	    = CONST_WIDE_INT_ELT (op, CONST_WIDE_INT_NUNITS (op) - 1);
+	  return (wide_int::sext (x, prec & (HOST_BITS_PER_WIDE_INT - 1))
+		  == x);
+	}
+    }
+  return 1;
+}
+
+/* Returns 1 if OP is an operand that is a CONST_WIDE_INT of mode
+   MODE.  This most likely is not as useful as
+   const_scalar_int_operand, but is here for consistancy.  */
+int
+const_wide_int_operand (rtx op, enum machine_mode mode)
+{
+  if (!CONST_WIDE_INT_P (op))
+    return 0;
+
+  return const_scalar_int_operand (op, mode);
+}
+
 /* Returns 1 if OP is an operand that is a constant integer or constant
-   floating-point number.  */
+   floating-point number of MODE.  */
+
+int
+const_double_operand (rtx op, enum machine_mode mode)
+{
+  return (GET_CODE (op) == CONST_DOUBLE)
+	  && (GET_MODE (op) == mode || mode == VOIDmode);
+}
+#else
+/* Returns 1 if OP is an operand that is a constant integer or constant
+   floating-point number of MODE.  */
 
 int
 const_double_operand (rtx op, enum machine_mode mode)
@@ -1175,8 +1231,9 @@ const_double_operand (rtx op, enum machine_mode mode)
 	  && (mode == VOIDmode || GET_MODE (op) == mode
 	      || GET_MODE (op) == VOIDmode));
 }
-
-/* Return 1 if OP is a general operand that is not an immediate operand.  */
+#endif
+/* Return 1 if OP is a general operand that is not an immediate
+   operand of mode MODE.  */
 
 int
 nonimmediate_operand (rtx op, enum machine_mode mode)
@@ -1184,7 +1241,8 @@ nonimmediate_operand (rtx op, enum machine_mode mode)
   return (general_operand (op, mode) && ! CONSTANT_P (op));
 }
 
-/* Return 1 if OP is a register reference or immediate value of mode MODE.  */
+/* Return 1 if OP is a register reference or immediate value of mode
+   MODE.  */
 
 int
 nonmemory_operand (rtx op, enum machine_mode mode)
diff --git a/gcc/rtl.c b/gcc/rtl.c
index c42abda..f7078e1 100644
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -111,7 +111,7 @@ const enum rtx_class rtx_class[NUM_RTX_CODE] = {
 const unsigned char rtx_code_size[NUM_RTX_CODE] = {
 #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)				\
   (((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE			\
-    || (ENUM) == CONST_FIXED)						\
+    || (ENUM) == CONST_FIXED || (ENUM) == CONST_WIDE_INT)		\
    ? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT)	\
    : RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (rtunion)),
 
@@ -183,18 +183,24 @@ shallow_copy_rtvec (rtvec vec)
 unsigned int
 rtx_size (const_rtx x)
 {
+  if (CONST_WIDE_INT_P (x))
+    return (RTX_HDR_SIZE
+	    + sizeof (struct hwivec_def)
+	    + ((CONST_WIDE_INT_NUNITS (x) - 1)
+	       * sizeof (HOST_WIDE_INT)));
   if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_HAS_BLOCK_INFO_P (x))
     return RTX_HDR_SIZE + sizeof (struct block_symbol);
   return RTX_CODE_SIZE (GET_CODE (x));
 }
 
-/* Allocate an rtx of code CODE.  The CODE is stored in the rtx;
-   all the rest is initialized to zero.  */
+/* Allocate an rtx of code CODE with EXTRA bytes in it.  The CODE is
+   stored in the rtx; all the rest is initialized to zero.  */
 
 rtx
-rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
+rtx_alloc_stat_v (RTX_CODE code MEM_STAT_DECL, int extra)
 {
-  rtx rt = ggc_alloc_zone_rtx_def_stat (&rtl_zone, RTX_CODE_SIZE (code)
+  rtx rt = ggc_alloc_zone_rtx_def_stat (&rtl_zone,
+					RTX_CODE_SIZE (code) + extra
                                         PASS_MEM_STAT);
 
   /* We want to clear everything up to the FLD array.  Normally, this
@@ -213,6 +219,29 @@ rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
   return rt;
 }
 
+/* Allocate an rtx of code CODE.  The CODE is stored in the rtx;
+   all the rest is initialized to zero.  */
+
+rtx
+rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
+{
+  return rtx_alloc_stat_v (code PASS_MEM_STAT, 0);
+}
+
+/* Write the wide constant OP0 to OUTFILE.  */
+
+void
+hwivec_output_hex (FILE *outfile, const_hwivec op0)
+{
+  int i = HWI_GET_NUM_ELEM (op0);
+  gcc_assert (i > 0);
+  if (XHWIVEC_ELT (op0, i-1) == 0)
+    fprintf (outfile, "0x");
+  fprintf (outfile, HOST_WIDE_INT_PRINT_HEX, XHWIVEC_ELT (op0, --i));
+  while (--i >= 0)
+    fprintf (outfile, HOST_WIDE_INT_PRINT_PADDED_HEX, XHWIVEC_ELT (op0, i));
+}
+
 \f
 /* Return true if ORIG is a sharable CONST.  */
 
@@ -427,7 +456,6 @@ rtx_equal_p_cb (const_rtx x, const_rtx y, rtx_equal_p_callback_function cb)
 	  if (XWINT (x, i) != XWINT (y, i))
 	    return 0;
 	  break;
-
 	case 'n':
 	case 'i':
 	  if (XINT (x, i) != XINT (y, i))
@@ -645,6 +673,10 @@ iterative_hash_rtx (const_rtx x, hashval_t hash)
       return iterative_hash_object (i, hash);
     case CONST_INT:
       return iterative_hash_object (INTVAL (x), hash);
+    case CONST_WIDE_INT:
+      for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	hash = iterative_hash_object (CONST_WIDE_INT_ELT (x, i), hash);
+      return hash;
     case SYMBOL_REF:
       if (XSTR (x, 0))
 	return iterative_hash (XSTR (x, 0), strlen (XSTR (x, 0)) + 1,
@@ -810,6 +842,16 @@ rtl_check_failed_block_symbol (const char *file, int line, const char *func)
 
 /* XXX Maybe print the vector?  */
 void
+hwivec_check_failed_bounds (const_hwivec r, int n, const char *file, int line,
+			    const char *func)
+{
+  internal_error
+    ("RTL check: access of hwi elt %d of vector with last elt %d in %s, at %s:%d",
+     n, GET_NUM_ELEM (r) - 1, func, trim_filename (file), line);
+}
+
+/* XXX Maybe print the vector?  */
+void
 rtvec_check_failed_bounds (const_rtvec r, int n, const char *file, int line,
 			   const char *func)
 {
diff --git a/gcc/rtl.def b/gcc/rtl.def
index 6948bfe..a38161f 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -319,6 +319,9 @@ DEF_RTL_EXPR(TRAP_IF, "trap_if", "ee", RTX_EXTRA)
 /* numeric integer constant */
 DEF_RTL_EXPR(CONST_INT, "const_int", "w", RTX_CONST_OBJ)
 
+/* numeric integer constant */
+DEF_RTL_EXPR(CONST_WIDE_INT, "const_wide_int", "", RTX_CONST_OBJ)
+
 /* fixed-point constant */
 DEF_RTL_EXPR(CONST_FIXED, "const_fixed", "www", RTX_CONST_OBJ)
 
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 90b1342..4c1c0c5 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "fixed-value.h"
 #include "alias.h"
 #include "hashtab.h"
+#include "wide-int.h"
 #include "flags.h"
 
 /* Value used by some passes to "recognize" noop moves as valid
@@ -251,6 +252,14 @@ struct GTY(()) object_block {
   vec<rtx, va_gc> *anchors;
 };
 
+struct GTY((variable_size)) hwivec_def {
+  int num_elem;		/* number of elements */
+  HOST_WIDE_INT elem[1];
+};
+
+#define HWI_GET_NUM_ELEM(HWIVEC)	((HWIVEC)->num_elem)
+#define HWI_PUT_NUM_ELEM(HWIVEC, NUM)	((HWIVEC)->num_elem = (NUM))
+
 /* RTL expression ("rtx").  */
 
 struct GTY((chain_next ("RTX_NEXT (&%h)"),
@@ -345,6 +354,7 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"),
     struct block_symbol block_sym;
     struct real_value rv;
     struct fixed_value fv;
+    struct hwivec_def hwiv;
   } GTY ((special ("rtx_def"), desc ("GET_CODE (&%0)"))) u;
 };
 
@@ -383,13 +393,13 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"),
    for a variable number of things.  The principle use is inside
    PARALLEL expressions.  */
 
+#define NULL_RTVEC (rtvec) 0
+
 struct GTY((variable_size)) rtvec_def {
   int num_elem;		/* number of elements */
   rtx GTY ((length ("%h.num_elem"))) elem[1];
 };
 
-#define NULL_RTVEC (rtvec) 0
-
 #define GET_NUM_ELEM(RTVEC)		((RTVEC)->num_elem)
 #define PUT_NUM_ELEM(RTVEC, NUM)	((RTVEC)->num_elem = (NUM))
 
@@ -399,12 +409,38 @@ struct GTY((variable_size)) rtvec_def {
 /* Predicate yielding nonzero iff X is an rtx for a memory location.  */
 #define MEM_P(X) (GET_CODE (X) == MEM)
 
+#if TARGET_SUPPORTS_WIDE_INT
+
+/* Match CONST_*s that can represent compile-time constant integers.  */
+#define CASE_CONST_SCALAR_INT \
+   case CONST_INT: \
+   case CONST_WIDE_INT
+
+/* Match CONST_*s for which pointer equality corresponds to value 
+   equality.  */
+#define CASE_CONST_UNIQUE \
+   case CONST_INT: \
+   case CONST_WIDE_INT: \
+   case CONST_DOUBLE: \
+   case CONST_FIXED
+
+/* Match all CONST_* rtxes.  */
+#define CASE_CONST_ANY \
+   case CONST_INT: \
+   case CONST_WIDE_INT: \
+   case CONST_DOUBLE: \
+   case CONST_FIXED: \
+   case CONST_VECTOR
+
+#else
+
 /* Match CONST_*s that can represent compile-time constant integers.  */
 #define CASE_CONST_SCALAR_INT \
    case CONST_INT: \
    case CONST_DOUBLE
 
-/* Match CONST_*s for which pointer equality corresponds to value equality.  */
+/* Match CONST_*s for which pointer equality corresponds to value 
+equality.  */
 #define CASE_CONST_UNIQUE \
    case CONST_INT: \
    case CONST_DOUBLE: \
@@ -416,10 +452,17 @@ struct GTY((variable_size)) rtvec_def {
    case CONST_DOUBLE: \
    case CONST_FIXED: \
    case CONST_VECTOR
+#endif
+
+
+
 
 /* Predicate yielding nonzero iff X is an rtx for a constant integer.  */
 #define CONST_INT_P(X) (GET_CODE (X) == CONST_INT)
 
+/* Predicate yielding nonzero iff X is an rtx for a constant integer.  */
+#define CONST_WIDE_INT_P(X) (GET_CODE (X) == CONST_WIDE_INT)
+
 /* Predicate yielding nonzero iff X is an rtx for a constant fixed-point.  */
 #define CONST_FIXED_P(X) (GET_CODE (X) == CONST_FIXED)
 
@@ -432,8 +475,13 @@ struct GTY((variable_size)) rtvec_def {
   (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == VOIDmode)
 
 /* Predicate yielding true iff X is an rtx for a integer const.  */
+#if TARGET_SUPPORTS_WIDE_INT
+#define CONST_SCALAR_INT_P(X) \
+  (CONST_INT_P (X) || CONST_WIDE_INT_P (X))
+#else
 #define CONST_SCALAR_INT_P(X) \
   (CONST_INT_P (X) || CONST_DOUBLE_AS_INT_P (X))
+#endif
 
 /* Predicate yielding true iff X is an rtx for a double-int.  */
 #define CONST_DOUBLE_AS_FLOAT_P(X) \
@@ -596,6 +644,13 @@ struct GTY((variable_size)) rtvec_def {
 			       __FUNCTION__);				\
      &_rtx->u.hwint[_n]; }))
 
+#define XHWIVEC_ELT(HWIVEC, I) __extension__				\
+(*({ __typeof (HWIVEC) const _hwivec = (HWIVEC); const int _i = (I);	\
+     if (_i < 0 || _i >= HWI_GET_NUM_ELEM (_hwivec))			\
+       hwivec_check_failed_bounds (_hwivec, _i, __FILE__, __LINE__,	\
+				  __FUNCTION__);			\
+     &_hwivec->elem[_i]; }))
+
 #define XCWINT(RTX, N, C) __extension__					\
 (*({ __typeof (RTX) const _rtx = (RTX);					\
      if (GET_CODE (_rtx) != (C))					\
@@ -632,6 +687,11 @@ struct GTY((variable_size)) rtvec_def {
 				    __FUNCTION__);			\
    &_symbol->u.block_sym; })
 
+#define HWIVEC_CHECK(RTX,C) __extension__				\
+({ __typeof (RTX) const _symbol = (RTX);				\
+   RTL_CHECKC1 (_symbol, 0, C);						\
+   &_symbol->u.hwiv; })
+
 extern void rtl_check_failed_bounds (const_rtx, int, const char *, int,
 				     const char *)
     ATTRIBUTE_NORETURN;
@@ -652,6 +712,9 @@ extern void rtl_check_failed_code_mode (const_rtx, enum rtx_code, enum machine_m
     ATTRIBUTE_NORETURN;
 extern void rtl_check_failed_block_symbol (const char *, int, const char *)
     ATTRIBUTE_NORETURN;
+extern void hwivec_check_failed_bounds (const_rtvec, int, const char *, int,
+					const char *)
+    ATTRIBUTE_NORETURN;
 extern void rtvec_check_failed_bounds (const_rtvec, int, const char *, int,
 				       const char *)
     ATTRIBUTE_NORETURN;
@@ -664,12 +727,14 @@ extern void rtvec_check_failed_bounds (const_rtvec, int, const char *, int,
 #define RTL_CHECKC2(RTX, N, C1, C2) ((RTX)->u.fld[N])
 #define RTVEC_ELT(RTVEC, I)	    ((RTVEC)->elem[I])
 #define XWINT(RTX, N)		    ((RTX)->u.hwint[N])
+#define XHWIVEC_ELT(HWIVEC, I)	    ((HWIVEC)->elem[I])
 #define XCWINT(RTX, N, C)	    ((RTX)->u.hwint[N])
 #define XCMWINT(RTX, N, C, M)	    ((RTX)->u.hwint[N])
 #define XCNMWINT(RTX, N, C, M)	    ((RTX)->u.hwint[N])
 #define XCNMPRV(RTX, C, M)	    (&(RTX)->u.rv)
 #define XCNMPFV(RTX, C, M)	    (&(RTX)->u.fv)
 #define BLOCK_SYMBOL_CHECK(RTX)	    (&(RTX)->u.block_sym)
+#define HWIVEC_CHECK(RTX,C)	    (&(RTX)->u.hwiv)
 
 #endif
 
@@ -812,8 +877,8 @@ extern void rtl_check_failed_flag (const char *, const_rtx, const char *,
 #define XCCFI(RTX, N, C)      (RTL_CHECKC1 (RTX, N, C).rt_cfi)
 #define XCCSELIB(RTX, N, C)   (RTL_CHECKC1 (RTX, N, C).rt_cselib)
 
-#define XCVECEXP(RTX, N, M, C)	RTVEC_ELT (XCVEC (RTX, N, C), M)
-#define XCVECLEN(RTX, N, C)	GET_NUM_ELEM (XCVEC (RTX, N, C))
+#define XCVECEXP(RTX, N, M, C) RTVEC_ELT (XCVEC (RTX, N, C), M)
+#define XCVECLEN(RTX, N, C)    GET_NUM_ELEM (XCVEC (RTX, N, C))
 
 #define XC2EXP(RTX, N, C1, C2)      (RTL_CHECKC2 (RTX, N, C1, C2).rt_rtx)
 \f
@@ -1155,9 +1220,19 @@ rhs_regno (const_rtx x)
 #define INTVAL(RTX) XCWINT(RTX, 0, CONST_INT)
 #define UINTVAL(RTX) ((unsigned HOST_WIDE_INT) INTVAL (RTX))
 
+/* For a CONST_WIDE_INT, CONST_WIDE_INT_NUNITS is the number of
+   elements actually needed to represent the constant.
+   CONST_WIDE_INT_ELT gets one of the elements.  0 is the least
+   significant HOST_WIDE_INT.  */
+#define CONST_WIDE_INT_VEC(RTX) HWIVEC_CHECK (RTX, CONST_WIDE_INT)
+#define CONST_WIDE_INT_NUNITS(RTX) HWI_GET_NUM_ELEM (CONST_WIDE_INT_VEC (RTX))
+#define CONST_WIDE_INT_ELT(RTX, N) XHWIVEC_ELT (CONST_WIDE_INT_VEC (RTX), N) 
+
 /* For a CONST_DOUBLE:
+#if TARGET_SUPPORTS_WIDE_INT == 0
    For a VOIDmode, there are two integers CONST_DOUBLE_LOW is the
      low-order word and ..._HIGH the high-order.
+#endif
    For a float, there is a REAL_VALUE_TYPE structure, and
      CONST_DOUBLE_REAL_VALUE(r) is a pointer to it.  */
 #define CONST_DOUBLE_LOW(r) XCMWINT (r, 0, CONST_DOUBLE, VOIDmode)
@@ -1762,6 +1837,12 @@ extern rtx plus_constant (enum machine_mode, rtx, HOST_WIDE_INT);
 /* In rtl.c */
 extern rtx rtx_alloc_stat (RTX_CODE MEM_STAT_DECL);
 #define rtx_alloc(c) rtx_alloc_stat (c MEM_STAT_INFO)
+extern rtx rtx_alloc_stat_v (RTX_CODE MEM_STAT_DECL, int);
+#define rtx_alloc_v(c, SZ) rtx_alloc_stat_v (c MEM_STAT_INFO, SZ)
+#define const_wide_int_alloc(NWORDS)				\
+  rtx_alloc_v (CONST_WIDE_INT,					\
+	       (sizeof (struct hwivec_def)			\
+		+ ((NWORDS)-1) * sizeof (HOST_WIDE_INT)))	\
 
 extern rtvec rtvec_alloc (int);
 extern rtvec shallow_copy_rtvec (rtvec);
@@ -1818,10 +1899,17 @@ extern void start_sequence (void);
 extern void push_to_sequence (rtx);
 extern void push_to_sequence2 (rtx, rtx);
 extern void end_sequence (void);
+#if TARGET_SUPPORTS_WIDE_INT == 0
 extern double_int rtx_to_double_int (const_rtx);
-extern rtx immed_double_int_const (double_int, enum machine_mode);
+#endif
+extern void hwivec_output_hex (FILE *, const_hwivec);
+#ifndef GENERATOR_FILE
+extern rtx immed_wide_int_const (const wide_int &cst, enum machine_mode mode);
+#endif
+#if TARGET_SUPPORTS_WIDE_INT == 0
 extern rtx immed_double_const (HOST_WIDE_INT, HOST_WIDE_INT,
 			       enum machine_mode);
+#endif
 
 /* In loop-iv.c  */
 
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 3826481..e76ce18 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -3096,6 +3096,8 @@ commutative_operand_precedence (rtx op)
   /* Constants always come the second operand.  Prefer "nice" constants.  */
   if (code == CONST_INT)
     return -8;
+  if (code == CONST_WIDE_INT)
+    return -8;
   if (code == CONST_DOUBLE)
     return -7;
   if (code == CONST_FIXED)
@@ -3108,6 +3110,8 @@ commutative_operand_precedence (rtx op)
     case RTX_CONST_OBJ:
       if (code == CONST_INT)
         return -6;
+      if (code == CONST_WIDE_INT)
+        return -6;
       if (code == CONST_DOUBLE)
         return -5;
       if (code == CONST_FIXED)
@@ -5294,7 +5298,10 @@ get_address_mode (rtx mem)
 /* Split up a CONST_DOUBLE or integer constant rtx
    into two rtx's for single words,
    storing in *FIRST the word that comes first in memory in the target
-   and in *SECOND the other.  */
+   and in *SECOND the other. 
+
+   TODO: This function needs to be rewritten to work on any size
+   integer.  */
 
 void
 split_double (rtx value, rtx *first, rtx *second)
@@ -5371,6 +5378,22 @@ split_double (rtx value, rtx *first, rtx *second)
 	    }
 	}
     }
+  else if (GET_CODE (value) == CONST_WIDE_INT)
+    {
+      /* All of this is scary code and needs to be converted to
+	 properly work with any size integer.  */
+      gcc_assert (CONST_WIDE_INT_NUNITS (value) == 2);
+      if (WORDS_BIG_ENDIAN)
+	{
+	  *first = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+	  *second = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+	}
+      else
+	{
+	  *first = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+	  *second = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+	}
+    }
   else if (!CONST_DOUBLE_P (value))
     {
       if (WORDS_BIG_ENDIAN)
diff --git a/gcc/sched-vis.c b/gcc/sched-vis.c
index 9572a47..27b57a7 100644
--- a/gcc/sched-vis.c
+++ b/gcc/sched-vis.c
@@ -444,6 +444,23 @@ print_value (char *buf, const_rtx x, int verbose)
 	       (unsigned HOST_WIDE_INT) INTVAL (x));
       cur = safe_concat (buf, cur, t);
       break;
+
+    case CONST_WIDE_INT:
+      {
+	const char *sep = "<";
+	int i;
+	for (i = CONST_WIDE_INT_NUNITS (x) - 1; i >= 0; i--)
+	  {
+	    cur = safe_concat (buf, cur, sep);
+	    sep = ",";
+	    sprintf (t, HOST_WIDE_INT_PRINT_HEX,
+		     (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, i));
+	    cur = safe_concat (buf, cur, t);
+	  }
+	cur = safe_concat (buf, cur, ">");
+      }
+      break;
+
     case CONST_DOUBLE:
       if (FLOAT_MODE_P (GET_MODE (x)))
 	real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0, 1);
diff --git a/gcc/sel-sched-ir.c b/gcc/sel-sched-ir.c
index 2c0403c..c84d8af 100644
--- a/gcc/sel-sched-ir.c
+++ b/gcc/sel-sched-ir.c
@@ -1139,10 +1139,10 @@ lhs_and_rhs_separable_p (rtx lhs, rtx rhs)
   if (lhs == NULL || rhs == NULL)
     return false;
 
-  /* Do not schedule CONST, CONST_INT and CONST_DOUBLE etc as rhs: no point
-     to use reg, if const can be used.  Moreover, scheduling const as rhs may
-     lead to mode mismatch cause consts don't have modes but they could be
-     merged from branches where the same const used in different modes.  */
+  /* Do not schedule constants as rhs: no point to use reg, if const
+     can be used.  Moreover, scheduling const as rhs may lead to mode
+     mismatch cause consts don't have modes but they could be merged
+     from branches where the same const used in different modes.  */
   if (CONSTANT_P (rhs))
     return false;
 
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 46d9e8a..9bbad7a 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -88,6 +88,22 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
   if (width <= HOST_BITS_PER_WIDE_INT
       && CONST_INT_P (x))
     val = INTVAL (x);
+#if TARGET_SUPPORTS_WIDE_INT
+  else if (CONST_WIDE_INT_P (x))
+    {
+      unsigned int i;
+      unsigned int elts = CONST_WIDE_INT_NUNITS (x);
+      if (elts != (width + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+	return false;
+      for (i = 0; i < elts - 1; i++)
+	if (CONST_WIDE_INT_ELT (x, i) != 0)
+	  return false;
+      val = CONST_WIDE_INT_ELT (x, elts - 1);
+      width %= HOST_BITS_PER_WIDE_INT;
+      if (width == 0)
+	width = HOST_BITS_PER_WIDE_INT;
+    }
+#else
   else if (width <= HOST_BITS_PER_DOUBLE_INT
 	   && CONST_DOUBLE_AS_INT_P (x)
 	   && CONST_DOUBLE_LOW (x) == 0)
@@ -95,8 +111,9 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
       val = CONST_DOUBLE_HIGH (x);
       width -= HOST_BITS_PER_WIDE_INT;
     }
+#endif
   else
-    /* FIXME: We don't yet have a representation for wider modes.  */
+    /* X is not an integer constant.  */
     return false;
 
   if (width < HOST_BITS_PER_WIDE_INT)
@@ -1460,7 +1477,6 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 				rtx op, enum machine_mode op_mode)
 {
   unsigned int width = GET_MODE_PRECISION (mode);
-  unsigned int op_width = GET_MODE_PRECISION (op_mode);
 
   if (code == VEC_DUPLICATE)
     {
@@ -1534,8 +1550,19 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       if (CONST_INT_P (op))
 	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
       else
+#if TARGET_SUPPORTS_WIDE_INT
+	{
+	  /* The conversion code to floats really want exactly 2 HWIs.
+	     This needs to be fixed.  For now, if the constant is
+	     really big, just return 0 which is safe.  */
+	  if (CONST_WIDE_INT_NUNITS (op) > 2)
+	    return 0;
+	  lv = CONST_WIDE_INT_ELT (op, 0);
+	  hv = CONST_WIDE_INT_ELT (op, 1);
+	}
+#else
 	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
-
+#endif
       REAL_VALUE_FROM_INT (d, lv, hv, mode);
       d = real_value_truncate (mode, d);
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
@@ -1548,8 +1575,19 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       if (CONST_INT_P (op))
 	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
       else
+#if TARGET_SUPPORTS_WIDE_INT
+	{
+	  /* The conversion code to floats really want exactly 2 HWIs.
+	     This needs to be fixed.  For now, if the constant is
+	     really big, just return 0 which is safe.  */
+	  if (CONST_WIDE_INT_NUNITS (op) > 2)
+	    return 0;
+	  lv = CONST_WIDE_INT_ELT (op, 0);
+	  hv = CONST_WIDE_INT_ELT (op, 1);
+	}
+#else
 	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
-
+#endif
       if (op_mode == VOIDmode
 	  || GET_MODE_PRECISION (op_mode) > HOST_BITS_PER_DOUBLE_INT)
 	/* We should never get a negative number.  */
@@ -1562,302 +1600,87 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
 
-  if (CONST_INT_P (op)
-      && width <= HOST_BITS_PER_WIDE_INT && width > 0)
+  if (CONST_SCALAR_INT_P (op) && width > 0)
     {
-      HOST_WIDE_INT arg0 = INTVAL (op);
-      HOST_WIDE_INT val;
+      wide_int result;
+      enum machine_mode imode = op_mode == VOIDmode ? mode : op_mode;
+      wide_int op0 = wide_int::from_rtx (op, imode);
+
+#if TARGET_SUPPORTS_WIDE_INT == 0
+      /* This assert keeps the simplification from producing a result
+	 that cannot be represented in a CONST_DOUBLE but a lot of
+	 upstream callers expect that this function never fails to
+	 simplify something and so you if you added this to the test
+	 above the code would die later anyway.  If this assert
+	 happens, you just need to make the port support wide int.  */
+      gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT); 
+#endif
 
       switch (code)
 	{
 	case NOT:
-	  val = ~ arg0;
+	  result = ~op0;
 	  break;
 
 	case NEG:
-	  val = - arg0;
+	  result = op0.neg ();
 	  break;
 
 	case ABS:
-	  val = (arg0 >= 0 ? arg0 : - arg0);
+	  result = op0.abs ();
 	  break;
 
 	case FFS:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = ffs_hwi (arg0);
+	  result = op0.ffs ();
 	  break;
 
 	case CLZ:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0 && CLZ_DEFINED_VALUE_AT_ZERO (mode, val))
-	    ;
-	  else
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 1;
+	  result = op0.clz (GET_MODE_BITSIZE (mode), 
+			    GET_MODE_PRECISION (mode));
 	  break;
 
 	case CLRSB:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0)
-	    val = GET_MODE_PRECISION (mode) - 1;
-	  else if (arg0 >= 0)
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 2;
-	  else if (arg0 < 0)
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (~arg0) - 2;
+	  result = op0.clrsb (GET_MODE_BITSIZE (mode), 
+			      GET_MODE_PRECISION (mode));
 	  break;
-
+	  
 	case CTZ:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0)
-	    {
-	      /* Even if the value at zero is undefined, we have to come
-		 up with some replacement.  Seems good enough.  */
-	      if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, val))
-		val = GET_MODE_PRECISION (mode);
-	    }
-	  else
-	    val = ctz_hwi (arg0);
+	  result = op0.ctz (GET_MODE_BITSIZE (mode), 
+			    GET_MODE_PRECISION (mode));
 	  break;
 
 	case POPCOUNT:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = 0;
-	  while (arg0)
-	    val++, arg0 &= arg0 - 1;
+	  result = op0.popcount (GET_MODE_BITSIZE (mode), 
+				 GET_MODE_PRECISION (mode));
 	  break;
 
 	case PARITY:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = 0;
-	  while (arg0)
-	    val++, arg0 &= arg0 - 1;
-	  val &= 1;
+	  result = op0.parity (GET_MODE_BITSIZE (mode), 
+			       GET_MODE_PRECISION (mode));
 	  break;
 
 	case BSWAP:
-	  {
-	    unsigned int s;
-
-	    val = 0;
-	    for (s = 0; s < width; s += 8)
-	      {
-		unsigned int d = width - s - 8;
-		unsigned HOST_WIDE_INT byte;
-		byte = (arg0 >> s) & 0xff;
-		val |= byte << d;
-	      }
-	  }
+	  result = op0.bswap ();
 	  break;
 
 	case TRUNCATE:
-	  val = arg0;
+	  result = op0.zforce_to_size (mode);
 	  break;
 
 	case ZERO_EXTEND:
-	  /* When zero-extending a CONST_INT, we need to know its
-             original mode.  */
-	  gcc_assert (op_mode != VOIDmode);
-	  if (op_width == HOST_BITS_PER_WIDE_INT)
-	    {
-	      /* If we were really extending the mode,
-		 we would have to distinguish between zero-extension
-		 and sign-extension.  */
-	      gcc_assert (width == op_width);
-	      val = arg0;
-	    }
-	  else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
-	    val = arg0 & GET_MODE_MASK (op_mode);
-	  else
-	    return 0;
+	  result = op0.zforce_to_size (mode);
 	  break;
 
 	case SIGN_EXTEND:
-	  if (op_mode == VOIDmode)
-	    op_mode = mode;
-	  op_width = GET_MODE_PRECISION (op_mode);
-	  if (op_width == HOST_BITS_PER_WIDE_INT)
-	    {
-	      /* If we were really extending the mode,
-		 we would have to distinguish between zero-extension
-		 and sign-extension.  */
-	      gcc_assert (width == op_width);
-	      val = arg0;
-	    }
-	  else if (op_width < HOST_BITS_PER_WIDE_INT)
-	    {
-	      val = arg0 & GET_MODE_MASK (op_mode);
-	      if (val_signbit_known_set_p (op_mode, val))
-		val |= ~GET_MODE_MASK (op_mode);
-	    }
-	  else
-	    return 0;
+	  result = op0.sforce_to_size (mode);
 	  break;
 
 	case SQRT:
-	case FLOAT_EXTEND:
-	case FLOAT_TRUNCATE:
-	case SS_TRUNCATE:
-	case US_TRUNCATE:
-	case SS_NEG:
-	case US_NEG:
-	case SS_ABS:
-	  return 0;
-
-	default:
-	  gcc_unreachable ();
-	}
-
-      return gen_int_mode (val, mode);
-    }
-
-  /* We can do some operations on integer CONST_DOUBLEs.  Also allow
-     for a DImode operation on a CONST_INT.  */
-  else if (width <= HOST_BITS_PER_DOUBLE_INT
-	   && (CONST_DOUBLE_AS_INT_P (op) || CONST_INT_P (op)))
-    {
-      double_int first, value;
-
-      if (CONST_DOUBLE_AS_INT_P (op))
-	first = double_int::from_pair (CONST_DOUBLE_HIGH (op),
-				       CONST_DOUBLE_LOW (op));
-      else
-	first = double_int::from_shwi (INTVAL (op));
-
-      switch (code)
-	{
-	case NOT:
-	  value = ~first;
-	  break;
-
-	case NEG:
-	  value = -first;
-	  break;
-
-	case ABS:
-	  if (first.is_negative ())
-	    value = -first;
-	  else
-	    value = first;
-	  break;
-
-	case FFS:
-	  value.high = 0;
-	  if (first.low != 0)
-	    value.low = ffs_hwi (first.low);
-	  else if (first.high != 0)
-	    value.low = HOST_BITS_PER_WIDE_INT + ffs_hwi (first.high);
-	  else
-	    value.low = 0;
-	  break;
-
-	case CLZ:
-	  value.high = 0;
-	  if (first.high != 0)
-	    value.low = GET_MODE_PRECISION (mode) - floor_log2 (first.high) - 1
-	              - HOST_BITS_PER_WIDE_INT;
-	  else if (first.low != 0)
-	    value.low = GET_MODE_PRECISION (mode) - floor_log2 (first.low) - 1;
-	  else if (! CLZ_DEFINED_VALUE_AT_ZERO (mode, value.low))
-	    value.low = GET_MODE_PRECISION (mode);
-	  break;
-
-	case CTZ:
-	  value.high = 0;
-	  if (first.low != 0)
-	    value.low = ctz_hwi (first.low);
-	  else if (first.high != 0)
-	    value.low = HOST_BITS_PER_WIDE_INT + ctz_hwi (first.high);
-	  else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, value.low))
-	    value.low = GET_MODE_PRECISION (mode);
-	  break;
-
-	case POPCOUNT:
-	  value = double_int_zero;
-	  while (first.low)
-	    {
-	      value.low++;
-	      first.low &= first.low - 1;
-	    }
-	  while (first.high)
-	    {
-	      value.low++;
-	      first.high &= first.high - 1;
-	    }
-	  break;
-
-	case PARITY:
-	  value = double_int_zero;
-	  while (first.low)
-	    {
-	      value.low++;
-	      first.low &= first.low - 1;
-	    }
-	  while (first.high)
-	    {
-	      value.low++;
-	      first.high &= first.high - 1;
-	    }
-	  value.low &= 1;
-	  break;
-
-	case BSWAP:
-	  {
-	    unsigned int s;
-
-	    value = double_int_zero;
-	    for (s = 0; s < width; s += 8)
-	      {
-		unsigned int d = width - s - 8;
-		unsigned HOST_WIDE_INT byte;
-
-		if (s < HOST_BITS_PER_WIDE_INT)
-		  byte = (first.low >> s) & 0xff;
-		else
-		  byte = (first.high >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff;
-
-		if (d < HOST_BITS_PER_WIDE_INT)
-		  value.low |= byte << d;
-		else
-		  value.high |= byte << (d - HOST_BITS_PER_WIDE_INT);
-	      }
-	  }
-	  break;
-
-	case TRUNCATE:
-	  /* This is just a change-of-mode, so do nothing.  */
-	  value = first;
-	  break;
-
-	case ZERO_EXTEND:
-	  gcc_assert (op_mode != VOIDmode);
-
-	  if (op_width > HOST_BITS_PER_WIDE_INT)
-	    return 0;
-
-	  value = double_int::from_uhwi (first.low & GET_MODE_MASK (op_mode));
-	  break;
-
-	case SIGN_EXTEND:
-	  if (op_mode == VOIDmode
-	      || op_width > HOST_BITS_PER_WIDE_INT)
-	    return 0;
-	  else
-	    {
-	      value.low = first.low & GET_MODE_MASK (op_mode);
-	      if (val_signbit_known_set_p (op_mode, value.low))
-		value.low |= ~GET_MODE_MASK (op_mode);
-
-	      value.high = HWI_SIGN_EXTEND (value.low);
-	    }
-	  break;
-
-	case SQRT:
-	  return 0;
-
 	default:
 	  return 0;
 	}
 
-      return immed_double_int_const (value, mode);
+      return immed_wide_int_const (result, mode);
     }
 
   else if (CONST_DOUBLE_AS_FLOAT_P (op) 
@@ -1909,7 +1732,6 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	}
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
-
   else if (CONST_DOUBLE_AS_FLOAT_P (op)
 	   && SCALAR_FLOAT_MODE_P (GET_MODE (op))
 	   && GET_MODE_CLASS (mode) == MODE_INT
@@ -1922,9 +1744,12 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 
       /* This was formerly used only for non-IEEE float.
 	 eggert@twinsun.com says it is safe for IEEE also.  */
-      HOST_WIDE_INT xh, xl, th, tl;
+      HOST_WIDE_INT th, tl;
       REAL_VALUE_TYPE x, t;
+      wide_int wc;
       REAL_VALUE_FROM_CONST_DOUBLE (x, op);
+      HOST_WIDE_INT tmp[2];
+
       switch (code)
 	{
 	case FIX:
@@ -1946,8 +1771,8 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  real_from_integer (&t, VOIDmode, tl, th, 0);
 	  if (REAL_VALUES_LESS (t, x))
 	    {
-	      xh = th;
-	      xl = tl;
+	      tmp[1] = th;
+	      tmp[0] = tl;
 	      break;
 	    }
 
@@ -1966,11 +1791,11 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  real_from_integer (&t, VOIDmode, tl, th, 0);
 	  if (REAL_VALUES_LESS (x, t))
 	    {
-	      xh = th;
-	      xl = tl;
+	      tmp[1] = th;
+	      tmp[0] = tl;
 	      break;
 	    }
-	  REAL_VALUE_TO_INT (&xl, &xh, x);
+	  REAL_VALUE_TO_INT (&tmp[0], &tmp[1], x);
 	  break;
 
 	case UNSIGNED_FIX:
@@ -1997,18 +1822,19 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  real_from_integer (&t, VOIDmode, tl, th, 1);
 	  if (REAL_VALUES_LESS (t, x))
 	    {
-	      xh = th;
-	      xl = tl;
+	      tmp[1] = th;
+	      tmp[0] = tl;
 	      break;
 	    }
 
-	  REAL_VALUE_TO_INT (&xl, &xh, x);
+	  REAL_VALUE_TO_INT (&tmp[0], &tmp[1], x);
 	  break;
 
 	default:
 	  gcc_unreachable ();
 	}
-      return immed_double_const (xl, xh, mode);
+      wc = wide_int::from_array (tmp, 2, mode);
+      return immed_wide_int_const (wc, mode);
     }
 
   return NULL_RTX;
@@ -2168,49 +1994,50 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       if (SCALAR_INT_MODE_P (mode))
 	{
-	  double_int coeff0, coeff1;
+	  wide_int coeff0;
+	  wide_int coeff1;
 	  rtx lhs = op0, rhs = op1;
 
-	  coeff0 = double_int_one;
-	  coeff1 = double_int_one;
+	  coeff0 = wide_int::one (mode);
+	  coeff1 = wide_int::one (mode);
 
 	  if (GET_CODE (lhs) == NEG)
 	    {
-	      coeff0 = double_int_minus_one;
+	      coeff0 = wide_int::minus_one (mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == MULT
-		   && CONST_INT_P (XEXP (lhs, 1)))
+		   && CONST_SCALAR_INT_P (XEXP (lhs, 1)))
 	    {
-	      coeff0 = double_int::from_shwi (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::from_rtx (XEXP (lhs, 1), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == ASHIFT
 		   && CONST_INT_P (XEXP (lhs, 1))
                    && INTVAL (XEXP (lhs, 1)) >= 0
-		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (lhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff0 = double_int_zero.set_bit (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::set_bit_in_zero (INTVAL (XEXP (lhs, 1)), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 
 	  if (GET_CODE (rhs) == NEG)
 	    {
-	      coeff1 = double_int_minus_one;
+	      coeff1 = wide_int::minus_one (mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == MULT
 		   && CONST_INT_P (XEXP (rhs, 1)))
 	    {
-	      coeff1 = double_int::from_shwi (INTVAL (XEXP (rhs, 1)));
+	      coeff1 = wide_int::from_rtx (XEXP (rhs, 1), mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == ASHIFT
 		   && CONST_INT_P (XEXP (rhs, 1))
 		   && INTVAL (XEXP (rhs, 1)) >= 0
-		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (rhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff1 = double_int_zero.set_bit (INTVAL (XEXP (rhs, 1)));
+	      coeff1 = wide_int::set_bit_in_zero (INTVAL (XEXP (rhs, 1)), mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 
@@ -2218,11 +2045,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	    {
 	      rtx orig = gen_rtx_PLUS (mode, op0, op1);
 	      rtx coeff;
-	      double_int val;
 	      bool speed = optimize_function_for_speed_p (cfun);
 
-	      val = coeff0 + coeff1;
-	      coeff = immed_double_int_const (val, mode);
+	      coeff = immed_wide_int_const (coeff0 + coeff1, mode);
 
 	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
 	      return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
@@ -2344,50 +2169,52 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       if (SCALAR_INT_MODE_P (mode))
 	{
-	  double_int coeff0, negcoeff1;
+	  wide_int coeff0;
+	  wide_int negcoeff1;
 	  rtx lhs = op0, rhs = op1;
 
-	  coeff0 = double_int_one;
-	  negcoeff1 = double_int_minus_one;
+	  coeff0 = wide_int::one (mode);
+	  negcoeff1 = wide_int::minus_one (mode);
 
 	  if (GET_CODE (lhs) == NEG)
 	    {
-	      coeff0 = double_int_minus_one;
+	      coeff0 = wide_int::minus_one (mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == MULT
-		   && CONST_INT_P (XEXP (lhs, 1)))
+		   && CONST_SCALAR_INT_P (XEXP (lhs, 1)))
 	    {
-	      coeff0 = double_int::from_shwi (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::from_rtx (XEXP (lhs, 1), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == ASHIFT
 		   && CONST_INT_P (XEXP (lhs, 1))
 		   && INTVAL (XEXP (lhs, 1)) >= 0
-		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (lhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff0 = double_int_zero.set_bit (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::set_bit_in_zero (INTVAL (XEXP (lhs, 1)), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 
 	  if (GET_CODE (rhs) == NEG)
 	    {
-	      negcoeff1 = double_int_one;
+	      negcoeff1 = wide_int::one (mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == MULT
 		   && CONST_INT_P (XEXP (rhs, 1)))
 	    {
-	      negcoeff1 = double_int::from_shwi (-INTVAL (XEXP (rhs, 1)));
+	      negcoeff1 = wide_int::from_rtx (XEXP (rhs, 1), mode).neg ();
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == ASHIFT
 		   && CONST_INT_P (XEXP (rhs, 1))
 		   && INTVAL (XEXP (rhs, 1)) >= 0
-		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (rhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      negcoeff1 = double_int_zero.set_bit (INTVAL (XEXP (rhs, 1)));
-	      negcoeff1 = -negcoeff1;
+	      negcoeff1 = wide_int::set_bit_in_zero (INTVAL (XEXP (rhs, 1)),
+						    mode);
+	      negcoeff1 = negcoeff1.neg ();
 	      rhs = XEXP (rhs, 0);
 	    }
 
@@ -2395,11 +2222,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	    {
 	      rtx orig = gen_rtx_MINUS (mode, op0, op1);
 	      rtx coeff;
-	      double_int val;
 	      bool speed = optimize_function_for_speed_p (cfun);
 
-	      val = coeff0 + negcoeff1;
-	      coeff = immed_double_int_const (val, mode);
+	      coeff = immed_wide_int_const (coeff0 + negcoeff1, mode);
 
 	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
 	      return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
@@ -2551,26 +2376,13 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	  && trueop1 == CONST1_RTX (mode))
 	return op0;
 
-      /* Convert multiply by constant power of two into shift unless
-	 we are still generating RTL.  This test is a kludge.  */
-      if (CONST_INT_P (trueop1)
-	  && (val = exact_log2 (UINTVAL (trueop1))) >= 0
-	  /* If the mode is larger than the host word size, and the
-	     uppermost bit is set, then this isn't a power of two due
-	     to implicit sign extension.  */
-	  && (width <= HOST_BITS_PER_WIDE_INT
-	      || val != HOST_BITS_PER_WIDE_INT - 1))
-	return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
-
-      /* Likewise for multipliers wider than a word.  */
-      if (CONST_DOUBLE_AS_INT_P (trueop1)
-	  && GET_MODE (op0) == mode
-	  && CONST_DOUBLE_LOW (trueop1) == 0
-	  && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0
-	  && (val < HOST_BITS_PER_DOUBLE_INT - 1
-	      || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT))
-	return simplify_gen_binary (ASHIFT, mode, op0,
-				    GEN_INT (val + HOST_BITS_PER_WIDE_INT));
+      /* Convert multiply by constant power of two into shift.  */
+      if (CONST_SCALAR_INT_P (trueop1))
+	{
+	  val = wide_int::from_rtx (trueop1, mode).exact_log2 ();
+	  if (val >= 0 && val < GET_MODE_BITSIZE (mode))
+	    return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
+	}
 
       /* x*2 is x+x and x*(-1) is -x */
       if (CONST_DOUBLE_AS_FLOAT_P (trueop1)
@@ -3609,9 +3421,9 @@ rtx
 simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 				 rtx op0, rtx op1)
 {
-  HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
-  HOST_WIDE_INT val;
+#if TARGET_SUPPORTS_WIDE_INT == 0
   unsigned int width = GET_MODE_PRECISION (mode);
+#endif
 
   if (VECTOR_MODE_P (mode)
       && code != VEC_CONCAT
@@ -3804,299 +3616,128 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
   /* We can fold some multi-word operations.  */
   if (GET_MODE_CLASS (mode) == MODE_INT
-      && width == HOST_BITS_PER_DOUBLE_INT
-      && (CONST_DOUBLE_AS_INT_P (op0) || CONST_INT_P (op0))
-      && (CONST_DOUBLE_AS_INT_P (op1) || CONST_INT_P (op1)))
+      && CONST_SCALAR_INT_P (op0)
+      && CONST_SCALAR_INT_P (op1))
     {
-      double_int o0, o1, res, tmp;
-      bool overflow;
-
-      o0 = rtx_to_double_int (op0);
-      o1 = rtx_to_double_int (op1);
-
+      wide_int result;
+      wide_int wop0 = wide_int::from_rtx (op0, mode);
+      wide_int wop1 = wide_int::from_rtx (op1, mode);
+      bool overflow = false;
+
+#if TARGET_SUPPORTS_WIDE_INT == 0
+      /* This assert keeps the simplification from producing a result
+	 that cannot be represented in a CONST_DOUBLE but a lot of
+	 upstream callers expect that this function never fails to
+	 simplify something and so you if you added this to the test
+	 above the code would die later anyway.  If this assert
+	 happens, you just need to make the port support wide int.  */
+      gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT);
+#endif
       switch (code)
 	{
 	case MINUS:
-	  /* A - B == A + (-B).  */
-	  o1 = -o1;
-
-	  /* Fall through....  */
+	  result = wop0 - wop1;
+	  break;
 
 	case PLUS:
-	  res = o0 + o1;
+	  result = wop0 + wop1;
 	  break;
 
 	case MULT:
-	  res = o0 * o1;
+	  result = wop0 * wop1;
 	  break;
 
 	case DIV:
-          res = o0.divmod_with_overflow (o1, false, TRUNC_DIV_EXPR,
-					 &tmp, &overflow);
+	  result = wop0.div_trunc (wop1, wide_int::SIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
-
+	  
 	case MOD:
-          tmp = o0.divmod_with_overflow (o1, false, TRUNC_DIV_EXPR,
-					 &res, &overflow);
+	  result = wop0.mod_trunc (wop1, wide_int::SIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case UDIV:
-          res = o0.divmod_with_overflow (o1, true, TRUNC_DIV_EXPR,
-					 &tmp, &overflow);
+	  result = wop0.div_trunc (wop1, wide_int::UNSIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case UMOD:
-          tmp = o0.divmod_with_overflow (o1, true, TRUNC_DIV_EXPR,
-					 &res, &overflow);
+	  result = wop0.mod_trunc (wop1, wide_int::UNSIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case AND:
-	  res = o0 & o1;
+	  result = wop0 & wop1;
 	  break;
 
 	case IOR:
-	  res = o0 | o1;
+	  result = wop0 | wop1;
 	  break;
 
 	case XOR:
-	  res = o0 ^ o1;
+	  result = wop0 ^ wop1;
 	  break;
 
 	case SMIN:
-	  res = o0.smin (o1);
+	  result = wop0.smin (wop1);
 	  break;
 
 	case SMAX:
-	  res = o0.smax (o1);
+	  result = wop0.smax (wop1);
 	  break;
 
 	case UMIN:
-	  res = o0.umin (o1);
+	  result = wop0.umin (wop1);
 	  break;
 
 	case UMAX:
-	  res = o0.umax (o1);
-	  break;
-
-	case LSHIFTRT:   case ASHIFTRT:
-	case ASHIFT:
-	case ROTATE:     case ROTATERT:
-	  {
-	    unsigned HOST_WIDE_INT cnt;
-
-	    if (SHIFT_COUNT_TRUNCATED)
-	      {
-		o1.high = 0; 
-		o1.low &= GET_MODE_PRECISION (mode) - 1;
-	      }
-
-	    if (!o1.fits_uhwi ()
-	        || o1.to_uhwi () >= GET_MODE_PRECISION (mode))
-	      return 0;
-
-	    cnt = o1.to_uhwi ();
-	    unsigned short prec = GET_MODE_PRECISION (mode);
-
-	    if (code == LSHIFTRT || code == ASHIFTRT)
-	      res = o0.rshift (cnt, prec, code == ASHIFTRT);
-	    else if (code == ASHIFT)
-	      res = o0.alshift (cnt, prec);
-	    else if (code == ROTATE)
-	      res = o0.lrotate (cnt, prec);
-	    else /* code == ROTATERT */
-	      res = o0.rrotate (cnt, prec);
-	  }
-	  break;
-
-	default:
-	  return 0;
-	}
-
-      return immed_double_int_const (res, mode);
-    }
-
-  if (CONST_INT_P (op0) && CONST_INT_P (op1)
-      && width <= HOST_BITS_PER_WIDE_INT && width != 0)
-    {
-      /* Get the integer argument values in two forms:
-         zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S.  */
-
-      arg0 = INTVAL (op0);
-      arg1 = INTVAL (op1);
-
-      if (width < HOST_BITS_PER_WIDE_INT)
-        {
-          arg0 &= GET_MODE_MASK (mode);
-          arg1 &= GET_MODE_MASK (mode);
-
-          arg0s = arg0;
-	  if (val_signbit_known_set_p (mode, arg0s))
-	    arg0s |= ~GET_MODE_MASK (mode);
-
-          arg1s = arg1;
-	  if (val_signbit_known_set_p (mode, arg1s))
-	    arg1s |= ~GET_MODE_MASK (mode);
-	}
-      else
-	{
-	  arg0s = arg0;
-	  arg1s = arg1;
-	}
-
-      /* Compute the value of the arithmetic.  */
-
-      switch (code)
-	{
-	case PLUS:
-	  val = arg0s + arg1s;
-	  break;
-
-	case MINUS:
-	  val = arg0s - arg1s;
-	  break;
-
-	case MULT:
-	  val = arg0s * arg1s;
-	  break;
-
-	case DIV:
-	  if (arg1s == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = arg0s / arg1s;
-	  break;
-
-	case MOD:
-	  if (arg1s == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = arg0s % arg1s;
+	  result = wop0.umax (wop1);
 	  break;
 
-	case UDIV:
-	  if (arg1 == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = (unsigned HOST_WIDE_INT) arg0 / arg1;
-	  break;
-
-	case UMOD:
-	  if (arg1 == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = (unsigned HOST_WIDE_INT) arg0 % arg1;
-	  break;
-
-	case AND:
-	  val = arg0 & arg1;
-	  break;
-
-	case IOR:
-	  val = arg0 | arg1;
-	  break;
+	case LSHIFTRT:
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	case XOR:
-	  val = arg0 ^ arg1;
+	  result = wop0.rshiftu (wop1, wide_int::TRUNC);
 	  break;
-
-	case LSHIFTRT:
-	case ASHIFT:
+	  
 	case ASHIFTRT:
-	  /* Truncate the shift if SHIFT_COUNT_TRUNCATED, otherwise make sure
-	     the value is in range.  We can't return any old value for
-	     out-of-range arguments because either the middle-end (via
-	     shift_truncation_mask) or the back-end might be relying on
-	     target-specific knowledge.  Nor can we rely on
-	     shift_truncation_mask, since the shift might not be part of an
-	     ashlM3, lshrM3 or ashrM3 instruction.  */
-	  if (SHIFT_COUNT_TRUNCATED)
-	    arg1 = (unsigned HOST_WIDE_INT) arg1 % width;
-	  else if (arg1 < 0 || arg1 >= GET_MODE_BITSIZE (mode))
-	    return 0;
-
-	  val = (code == ASHIFT
-		 ? ((unsigned HOST_WIDE_INT) arg0) << arg1
-		 : ((unsigned HOST_WIDE_INT) arg0) >> arg1);
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	  /* Sign-extend the result for arithmetic right shifts.  */
-	  if (code == ASHIFTRT && arg0s < 0 && arg1 > 0)
-	    val |= ((unsigned HOST_WIDE_INT) (-1)) << (width - arg1);
+	  result = wop0.rshifts (wop1, wide_int::TRUNC);
 	  break;
+	  
+	case ASHIFT:
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	case ROTATERT:
-	  if (arg1 < 0)
-	    return 0;
-
-	  arg1 %= width;
-	  val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
-		 | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
+	  result = wop0.lshift (wop1, wide_int::TRUNC);
 	  break;
-
+	  
 	case ROTATE:
-	  if (arg1 < 0)
-	    return 0;
-
-	  arg1 %= width;
-	  val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
-		 | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
-	  break;
-
-	case COMPARE:
-	  /* Do nothing here.  */
-	  return 0;
-
-	case SMIN:
-	  val = arg0s <= arg1s ? arg0s : arg1s;
-	  break;
-
-	case UMIN:
-	  val = ((unsigned HOST_WIDE_INT) arg0
-		 <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
-	  break;
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	case SMAX:
-	  val = arg0s > arg1s ? arg0s : arg1s;
+	  result = wop0.lrotate (wop1);
 	  break;
+	  
+	case ROTATERT:
+	  if (wop1.neg_p ())
+	    return NULL_RTX;
 
-	case UMAX:
-	  val = ((unsigned HOST_WIDE_INT) arg0
-		 > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
+	  result = wop0.rrotate (wop1);
 	  break;
 
-	case SS_PLUS:
-	case US_PLUS:
-	case SS_MINUS:
-	case US_MINUS:
-	case SS_MULT:
-	case US_MULT:
-	case SS_DIV:
-	case US_DIV:
-	case SS_ASHIFT:
-	case US_ASHIFT:
-	  /* ??? There are simplifications that can be done.  */
-	  return 0;
-
 	default:
-	  gcc_unreachable ();
+	  return NULL_RTX;
 	}
-
-      return gen_int_mode (val, mode);
+      return immed_wide_int_const (result, mode);
     }
 
   return NULL_RTX;
@@ -4764,10 +4405,11 @@ comparison_result (enum rtx_code code, int known_results)
     }
 }
 
-/* Check if the given comparison (done in the given MODE) is actually a
-   tautology or a contradiction.
-   If no simplification is possible, this function returns zero.
-   Otherwise, it returns either const_true_rtx or const0_rtx.  */
+/* Check if the given comparison (done in the given MODE) is actually
+   a tautology or a contradiction.  If the mode is VOID_mode, the
+   comparison is done in "infinite precision".  If no simplification
+   is possible, this function returns zero.  Otherwise, it returns
+   either const_true_rtx or const0_rtx.  */
 
 rtx
 simplify_const_relational_operation (enum rtx_code code,
@@ -4891,59 +4533,25 @@ simplify_const_relational_operation (enum rtx_code code,
 
   /* Otherwise, see if the operands are both integers.  */
   if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
-       && (CONST_DOUBLE_AS_INT_P (trueop0) || CONST_INT_P (trueop0))
-       && (CONST_DOUBLE_AS_INT_P (trueop1) || CONST_INT_P (trueop1)))
+      && CONST_SCALAR_INT_P (trueop0) && CONST_SCALAR_INT_P (trueop1))
     {
-      int width = GET_MODE_PRECISION (mode);
-      HOST_WIDE_INT l0s, h0s, l1s, h1s;
-      unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
-
-      /* Get the two words comprising each integer constant.  */
-      if (CONST_DOUBLE_AS_INT_P (trueop0))
-	{
-	  l0u = l0s = CONST_DOUBLE_LOW (trueop0);
-	  h0u = h0s = CONST_DOUBLE_HIGH (trueop0);
-	}
-      else
-	{
-	  l0u = l0s = INTVAL (trueop0);
-	  h0u = h0s = HWI_SIGN_EXTEND (l0s);
-	}
-
-      if (CONST_DOUBLE_AS_INT_P (trueop1))
-	{
-	  l1u = l1s = CONST_DOUBLE_LOW (trueop1);
-	  h1u = h1s = CONST_DOUBLE_HIGH (trueop1);
-	}
-      else
-	{
-	  l1u = l1s = INTVAL (trueop1);
-	  h1u = h1s = HWI_SIGN_EXTEND (l1s);
-	}
-
-      /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
-	 we have to sign or zero-extend the values.  */
-      if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
-	{
-	  l0u &= GET_MODE_MASK (mode);
-	  l1u &= GET_MODE_MASK (mode);
-
-	  if (val_signbit_known_set_p (mode, l0s))
-	    l0s |= ~GET_MODE_MASK (mode);
-
-	  if (val_signbit_known_set_p (mode, l1s))
-	    l1s |= ~GET_MODE_MASK (mode);
-	}
-      if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
-	h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
-
-      if (h0u == h1u && l0u == l1u)
+      enum machine_mode cmode = mode;
+      wide_int wo0;
+      wide_int wo1;
+
+      /* It would be nice if we really had a mode here.  However, the
+	 largest int representable on the target is as good as
+	 infinite.  */
+      if (mode == VOIDmode)
+	cmode = MAX_MODE_INT;
+      wo0 = wide_int::from_rtx (trueop0, cmode);
+      wo1 = wide_int::from_rtx (trueop1, cmode);
+      if (wo0 == wo1)
 	return comparison_result (code, CMP_EQ);
       else
 	{
-	  int cr;
-	  cr = (h0s < h1s || (h0s == h1s && l0u < l1u)) ? CMP_LT : CMP_GT;
-	  cr |= (h0u < h1u || (h0u == h1u && l0u < l1u)) ? CMP_LTU : CMP_GTU;
+	  int cr = wo0.lts_p (wo1) ? CMP_LT : CMP_GT;
+	  cr |= wo0.ltu_p (wo1) ? CMP_LTU : CMP_GTU;
 	  return comparison_result (code, cr);
 	}
     }
@@ -5358,9 +4966,9 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
   return 0;
 }
 
-/* Evaluate a SUBREG of a CONST_INT or CONST_DOUBLE or CONST_FIXED
-   or CONST_VECTOR,
-   returning another CONST_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
+/* Evaluate a SUBREG of a CONST_INT or CONST_WIDE_INT or CONST_DOUBLE
+   or CONST_FIXED or CONST_VECTOR, returning another CONST_INT or
+   CONST_WIDE_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
 
    Works by unpacking OP into a collection of 8-bit values
    represented as a little-endian array of 'unsigned char', selecting by BYTE,
@@ -5370,13 +4978,11 @@ static rtx
 simplify_immed_subreg (enum machine_mode outermode, rtx op,
 		       enum machine_mode innermode, unsigned int byte)
 {
-  /* We support up to 512-bit values (for V8DFmode).  */
   enum {
-    max_bitsize = 512,
     value_bit = 8,
     value_mask = (1 << value_bit) - 1
   };
-  unsigned char value[max_bitsize / value_bit];
+  unsigned char value[MAX_BITSIZE_MODE_ANY_MODE/value_bit];
   int value_start;
   int i;
   int elem;
@@ -5388,6 +4994,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
   rtvec result_v = NULL;
   enum mode_class outer_class;
   enum machine_mode outer_submode;
+  int max_bitsize;
 
   /* Some ports misuse CCmode.  */
   if (GET_MODE_CLASS (outermode) == MODE_CC && CONST_INT_P (op))
@@ -5397,6 +5004,10 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
   if (COMPLEX_MODE_P (outermode))
     return NULL_RTX;
 
+  /* We support any size mode.  */
+  max_bitsize = MAX (GET_MODE_BITSIZE (outermode), 
+		     GET_MODE_BITSIZE (innermode));
+
   /* Unpack the value.  */
 
   if (GET_CODE (op) == CONST_VECTOR)
@@ -5446,8 +5057,20 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	    *vp++ = INTVAL (el) < 0 ? -1 : 0;
 	  break;
 
+	case CONST_WIDE_INT:
+	  {
+	    wide_int val = wide_int::from_rtx (el, innermode);
+	    unsigned char extend = val.sign_mask ();
+
+	    for (i = 0; i < elem_bitsize; i += value_bit) 
+	      *vp++ = val.extract_to_hwi (i, value_bit);
+	    for (; i < elem_bitsize; i += value_bit)
+	      *vp++ = extend;
+	  }
+	  break;
+
 	case CONST_DOUBLE:
-	  if (GET_MODE (el) == VOIDmode)
+	  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (el) == VOIDmode)
 	    {
 	      unsigned char extend = 0;
 	      /* If this triggers, someone should have generated a
@@ -5470,7 +5093,8 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	    }
 	  else
 	    {
-	      long tmp[max_bitsize / 32];
+	      /* This is big enough for anything on the platform.  */
+	      long tmp[MAX_BITSIZE_MODE_ANY_MODE / 32];
 	      int bitsize = GET_MODE_BITSIZE (GET_MODE (el));
 
 	      gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (el)));
@@ -5590,24 +5214,27 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	case MODE_INT:
 	case MODE_PARTIAL_INT:
 	  {
-	    unsigned HOST_WIDE_INT hi = 0, lo = 0;
-
-	    for (i = 0;
-		 i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
-		 i += value_bit)
-	      lo |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
-	    for (; i < elem_bitsize; i += value_bit)
-	      hi |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask)
-		     << (i - HOST_BITS_PER_WIDE_INT);
-
-	    /* immed_double_const doesn't call trunc_int_for_mode.  I don't
-	       know why.  */
-	    if (elem_bitsize <= HOST_BITS_PER_WIDE_INT)
-	      elems[elem] = gen_int_mode (lo, outer_submode);
-	    else if (elem_bitsize <= HOST_BITS_PER_DOUBLE_INT)
-	      elems[elem] = immed_double_const (lo, hi, outer_submode);
-	    else
-	      return NULL_RTX;
+	    int u;
+	    int base = 0;
+	    int units 
+	      = (GET_MODE_BITSIZE (outer_submode) + HOST_BITS_PER_WIDE_INT - 1) 
+	      / HOST_BITS_PER_WIDE_INT;
+	    HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+	    wide_int r;
+
+	    for (u = 0; u < units; u++) 
+	      {
+		unsigned HOST_WIDE_INT buf = 0;
+		for (i = 0; 
+		     i < HOST_BITS_PER_WIDE_INT && base + i < elem_bitsize; 
+		     i += value_bit)
+		  buf |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
+
+		tmp[u] = buf;
+		base += HOST_BITS_PER_WIDE_INT;
+	      }
+	    r = wide_int::from_array (tmp, units, outer_submode);
+	    elems[elem] = immed_wide_int_const (r, outer_submode);
 	  }
 	  break;
 
@@ -5615,7 +5242,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	case MODE_DECIMAL_FLOAT:
 	  {
 	    REAL_VALUE_TYPE r;
-	    long tmp[max_bitsize / 32];
+	    long tmp[MAX_BITSIZE_MODE_ANY_INT / 32];
 
 	    /* real_from_target wants its input in words affected by
 	       FLOAT_WORDS_BIG_ENDIAN.  However, we ignore this,
diff --git a/gcc/tree-ssa-address.c b/gcc/tree-ssa-address.c
index 3b1e068..2f5397e 100644
--- a/gcc/tree-ssa-address.c
+++ b/gcc/tree-ssa-address.c
@@ -190,15 +190,18 @@ addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
   struct mem_addr_template *templ;
 
   if (addr->step && !integer_onep (addr->step))
-    st = immed_double_int_const (tree_to_double_int (addr->step), pointer_mode);
+    st = immed_wide_int_const (wide_int::from_tree (addr->step),
+			       TYPE_MODE (TREE_TYPE (addr->step)));
   else
     st = NULL_RTX;
 
   if (addr->offset && !integer_zerop (addr->offset))
-    off = immed_double_int_const
-	    (tree_to_double_int (addr->offset)
-	     .sext (TYPE_PRECISION (TREE_TYPE (addr->offset))),
-	     pointer_mode);
+    {
+      wide_int dc = wide_int::from_tree (addr->offset);
+      dc = dc.sforce_to_size (TREE_TYPE (addr->offset));
+      off = immed_wide_int_const (dc,
+			       TYPE_MODE (TREE_TYPE (addr->offset)));
+    }
   else
     off = NULL_RTX;
 
diff --git a/gcc/tree.c b/gcc/tree.c
index 7cacb2a..77ea03c 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -61,6 +61,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "except.h"
 #include "debug.h"
 #include "intl.h"
+#include "wide-int.h"
 
 /* Tree code classes.  */
 
@@ -1068,6 +1069,23 @@ double_int_to_tree (tree type, double_int cst)
   return build_int_cst_wide (type, cst.low, cst.high);
 }
 
+/* Constructs tree in type TYPE from with value given by CST.  Signedness
+   of CST is assumed to be the same as the signedness of TYPE.  */
+
+tree
+wide_int_to_tree (tree type, const wide_int &cst)
+{
+  wide_int v;
+
+  gcc_assert (cst.get_len () <= 2);
+  if (TYPE_UNSIGNED (type))
+    v = cst.zext (TYPE_PRECISION (type));
+  else
+    v = cst.sext (TYPE_PRECISION (type));
+
+  return build_int_cst_wide (type, v.elt (0), v.elt (1));
+}
+
 /* Returns true if CST fits into range of TYPE.  Signedness of CST is assumed
    to be the same as the signedness of TYPE.  */
 
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index f5ba115..a72bc3d 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -3381,6 +3381,23 @@ loc_cmp (rtx x, rtx y)
       default:
 	gcc_unreachable ();
       }
+  if (CONST_WIDE_INT_P (x))
+    {
+      /* Compare the vector length first.  */
+      if (CONST_WIDE_INT_NUNITS (x) >= CONST_WIDE_INT_NUNITS (y))
+	return 1;
+      else if (CONST_WIDE_INT_NUNITS (x) < CONST_WIDE_INT_NUNITS (y))
+	return -1;
+
+      /* Compare the vectors elements.  */;
+      for (j = CONST_WIDE_INT_NUNITS (x) - 1; j >= 0 ; j--)
+	{
+	  if (CONST_WIDE_INT_ELT (x, j) < CONST_WIDE_INT_ELT (y, j))
+	    return -1;
+	  if (CONST_WIDE_INT_ELT (x, j) > CONST_WIDE_INT_ELT (y, j))
+	    return 1;
+	}
+    }
 
   return 0;
 }
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 4598cf2..bfad851 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -3376,6 +3376,7 @@ const_rtx_hash_1 (rtx *xp, void *data)
   enum rtx_code code;
   hashval_t h, *hp;
   rtx x;
+  int i;
 
   x = *xp;
   code = GET_CODE (x);
@@ -3386,12 +3387,12 @@ const_rtx_hash_1 (rtx *xp, void *data)
     {
     case CONST_INT:
       hwi = INTVAL (x);
+
     fold_hwi:
       {
 	int shift = sizeof (hashval_t) * CHAR_BIT;
 	const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t);
-	int i;
-
+	
 	h ^= (hashval_t) hwi;
 	for (i = 1; i < n; ++i)
 	  {
@@ -3401,8 +3402,16 @@ const_rtx_hash_1 (rtx *xp, void *data)
       }
       break;
 
+    case CONST_WIDE_INT:
+      hwi = GET_MODE_PRECISION (mode);
+      {
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hwi ^= CONST_WIDE_INT_ELT (x, i);
+	goto fold_hwi;
+      }
+
     case CONST_DOUBLE:
-      if (mode == VOIDmode)
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && mode == VOIDmode)
 	{
 	  hwi = CONST_DOUBLE_LOW (x) ^ CONST_DOUBLE_HIGH (x);
 	  goto fold_hwi;

^ permalink raw reply	[flat|nested] 217+ messages in thread

* patch to add storage classes to wide int.
  2012-11-30 17:00                                                                           ` patch to fix constant math - 5th patch - the rtl level changes Kenneth Zadeck
@ 2012-11-30 18:13                                                                             ` Kenneth Zadeck
  2012-11-30 19:05                                                                               ` Kenneth Zadeck
  2012-12-01  9:28                                                                               ` Richard Sandiford
  0 siblings, 2 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-11-30 18:13 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, Lawrence Crowl, Richard Sandiford

Richi

this patch is our attempt to implement the storage classes for wide int 
as you suggested.   The patch currently does not work for reasons that 
will be mentioned below, but we stopped work on it because it is clear 
that this is a terrible idea.

1) Having more than one storage class is like having more than one 
register in an architecture:   1 register register allocation is easy, 
more than one register is np complete.  More than one storage class 
makes the code unreasonably complex.    While it is true that in many 
cases, this can be "hidden" with c++ magic, in a lot of places it cannot 
and the notion that all of this is free is just a myth.

The storage classes mechanism that you have suggested, is not 
polymorphic.   It is two separate classes for wide it, one that does 
pointer copying and one that stack allocates.   From the client's 
perspective, this does not appear too bad, just a lot of <> here and there.

But there are a lot of places where, at run time, it is not clear which 
of the two alternatives is going to be available.  Consider the 
following code:

wide_int<>::foo = wide_int<ptr>::from_rtx (x);

if (...)
    foo = foo + wide_int<ptr>::from_rtx (y);

Which type of wide-int does foo contain after the if-then.   It really 
could be either one and so one of the two has to be converted into the 
other one before the next use of foo.   I claimed, i believe correctly 
that data copying was not going to be any more expensive than pointer 
copying because the amount of data was so small.    But now, because we 
have more than one type, we have to deal with conversion.

2) The patch does not work for rtxes at all.   Rtxes have to copied.   
Trees could be pointer copied.
The problem is that CONST_INTs are not canonized in a way that wide-ints 
are or that trees could be.
This comes from the use of the GEN_INT macro that does not take a 
mode.   Without a mode, you do not get the integers into proper form: 
i.e. sign extended.  At the tree level, this is not a problem because 
the INT_CST constructors take a type.  But the best that can be done at 
the rtl level is to do the sign extension when we convert inside 
from_rtx (which takes a precision or a mode).

Fixing this is on Richard Sandiford's and my "it would be nice list" but 
is certainly out of the question to do as a prereq for this patch.

3) The patch seems to require that there be nothing in wide-int.c and 
everything in wide-int.h.    This is a lot of code to go into a header 
file that is likely to be included into almost every c file.   The 
current patch very carefully divides the implementation of each function 
into a fast, inlined  small case that handles all types that fit in an 
HWI and a larger general implementation that handles the rarely used 
large types.   That seems to have to go away to make the two different 
implementations of wide-int work.

4) I consider the resulting wide-int.h to be unreadable.    I am sure 
that after the proper indoctrination period, i will just accept this 
glop, but to the people in the community who have some apprehension 
about what gcc will turn into now that C++ is allowed, this seems like 
the poster child of where they did not want this to go.   The amount of 
c++ trickery employed here for what seems like i truly marginal gain 
seems to be out of proportion.

Mike and I gave this a good try, but in the end i think that it is 
better to not do this change.  I get it that having only one storage 
class is not going to give you a medium term large int rep.  But there 
are other ways to go
to get this.   We can simply define a class that is a medium term holder 
and copy the values into it.    Again, the copying is not that bad 
because it is almost always 1 element.

Kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to add storage classes to wide int.
  2012-11-30 18:13                                                                             ` patch to add storage classes to wide int Kenneth Zadeck
@ 2012-11-30 19:05                                                                               ` Kenneth Zadeck
  2012-12-01  9:28                                                                               ` Richard Sandiford
  1 sibling, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-11-30 19:05 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, Lawrence Crowl, Richard Sandiford

[-- Attachment #1: Type: text/plain, Size: 3977 bytes --]

forgot the patch
On 11/30/2012 01:03 PM, Kenneth Zadeck wrote:
> Richi
>
> this patch is our attempt to implement the storage classes for wide 
> int as you suggested.   The patch currently does not work for reasons 
> that will be mentioned below, but we stopped work on it because it is 
> clear that this is a terrible idea.
>
> 1) Having more than one storage class is like having more than one 
> register in an architecture:   1 register register allocation is easy, 
> more than one register is np complete.  More than one storage class 
> makes the code unreasonably complex.    While it is true that in many 
> cases, this can be "hidden" with c++ magic, in a lot of places it 
> cannot and the notion that all of this is free is just a myth.
>
> The storage classes mechanism that you have suggested, is not 
> polymorphic.   It is two separate classes for wide it, one that does 
> pointer copying and one that stack allocates.   From the client's 
> perspective, this does not appear too bad, just a lot of <> here and 
> there.
>
> But there are a lot of places where, at run time, it is not clear 
> which of the two alternatives is going to be available.  Consider the 
> following code:
>
> wide_int<>::foo = wide_int<ptr>::from_rtx (x);
>
> if (...)
>    foo = foo + wide_int<ptr>::from_rtx (y);
>
> Which type of wide-int does foo contain after the if-then.   It really 
> could be either one and so one of the two has to be converted into the 
> other one before the next use of foo.   I claimed, i believe correctly 
> that data copying was not going to be any more expensive than pointer 
> copying because the amount of data was so small.    But now, because 
> we have more than one type, we have to deal with conversion.
>
> 2) The patch does not work for rtxes at all.   Rtxes have to copied.   
> Trees could be pointer copied.
> The problem is that CONST_INTs are not canonized in a way that 
> wide-ints are or that trees could be.
> This comes from the use of the GEN_INT macro that does not take a 
> mode.   Without a mode, you do not get the integers into proper form: 
> i.e. sign extended.  At the tree level, this is not a problem because 
> the INT_CST constructors take a type.  But the best that can be done 
> at the rtl level is to do the sign extension when we convert inside 
> from_rtx (which takes a precision or a mode).
>
> Fixing this is on Richard Sandiford's and my "it would be nice list" 
> but is certainly out of the question to do as a prereq for this patch.
>
> 3) The patch seems to require that there be nothing in wide-int.c and 
> everything in wide-int.h.    This is a lot of code to go into a header 
> file that is likely to be included into almost every c file.   The 
> current patch very carefully divides the implementation of each 
> function into a fast, inlined  small case that handles all types that 
> fit in an HWI and a larger general implementation that handles the 
> rarely used large types.   That seems to have to go away to make the 
> two different implementations of wide-int work.
>
> 4) I consider the resulting wide-int.h to be unreadable.    I am sure 
> that after the proper indoctrination period, i will just accept this 
> glop, but to the people in the community who have some apprehension 
> about what gcc will turn into now that C++ is allowed, this seems like 
> the poster child of where they did not want this to go.   The amount 
> of c++ trickery employed here for what seems like i truly marginal 
> gain seems to be out of proportion.
>
> Mike and I gave this a good try, but in the end i think that it is 
> better to not do this change.  I get it that having only one storage 
> class is not going to give you a medium term large int rep.  But there 
> are other ways to go
> to get this.   We can simply define a class that is a medium term 
> holder and copy the values into it.    Again, the copying is not that 
> bad because it is almost always 1 element.
>
> Kenny
>


[-- Attachment #2: wide-1.diffs.bz2 --]
[-- Type: application/x-bzip, Size: 34853 bytes --]

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to add storage classes to wide int.
  2012-11-30 18:13                                                                             ` patch to add storage classes to wide int Kenneth Zadeck
  2012-11-30 19:05                                                                               ` Kenneth Zadeck
@ 2012-12-01  9:28                                                                               ` Richard Sandiford
  2012-12-01 13:43                                                                                 ` Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2012-12-01  9:28 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl

Kenneth Zadeck <zadeck@naturalbridge.com> writes:
> 2) The patch does not work for rtxes at all.   Rtxes have to copied.   
> Trees could be pointer copied.
> The problem is that CONST_INTs are not canonized in a way that wide-ints 
> are or that trees could be.
> This comes from the use of the GEN_INT macro that does not take a 
> mode.   Without a mode, you do not get the integers into proper form: 
> i.e. sign extended.  At the tree level, this is not a problem because 
> the INT_CST constructors take a type.  But the best that can be done at 
> the rtl level is to do the sign extension when we convert inside 
> from_rtx (which takes a precision or a mode).

rtxes must be sign-extended too, even under current rules.  If you have
a case where an rtx constant isn't sign-extended for the mode in which
it's being used, then either the constant wasn't created correctly or
the code that's calling from_rtx has got the wrong mode.  Those are bugs
even now.

This is enforced in some places already.  E.g. if an insn has a QImode
const_int_operand, (const_int 128) will not match (assuming 8 bits
per unit of course).

I can well imagine this patch hits cases that haven't been caught
yet though.

FWIW, I think the thing you mention here...

> Fixing this is on Richard Sandiford's and my "it would be nice list" but 
> is certainly out of the question to do as a prereq for this patch.

...is the idea of attaching the mode to the constant, rather than
having to keep track of it separately.  That's definitely still
something I'd like to do, but it wouldn't involve any changes to
the canonicalisation rules.

I still agree that abstracting the storage seems like an unnecessary
complication.  In the other thread, Richard B said:

> The patches introduce a lot more temporary wide-ints (your words) and
> at the same time makes construction of them from tree / rtx very expensive
> both stack space and compile-time wise.  Look at how we for example
> compute TREE_INT_CST + 1 - int_cst_binop internally uses double_ints
> for the computation and then instantiates a new tree for holding the result.
> Now we'd use wide_ints for this requring totally unnecessary copying.

But surely the expensive part of that operation is instantiating the
new tree, with its associated hash table lookup and potential allocation.
Trying to save one or two copies of integers from heap to stack seems
minor compared to that.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to add storage classes to wide int.
  2012-12-01  9:28                                                                               ` Richard Sandiford
@ 2012-12-01 13:43                                                                                 ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2012-12-01 13:43 UTC (permalink / raw)
  To: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford


On 12/01/2012 04:28 AM, Richard Sandiford wrote:
> Kenneth Zadeck <zadeck@naturalbridge.com> writes:
>> 2) The patch does not work for rtxes at all.   Rtxes have to copied.
>> Trees could be pointer copied.
>> The problem is that CONST_INTs are not canonized in a way that wide-ints
>> are or that trees could be.
>> This comes from the use of the GEN_INT macro that does not take a
>> mode.   Without a mode, you do not get the integers into proper form:
>> i.e. sign extended.  At the tree level, this is not a problem because
>> the INT_CST constructors take a type.  But the best that can be done at
>> the rtl level is to do the sign extension when we convert inside
>> from_rtx (which takes a precision or a mode).
> rtxes must be sign-extended too, even under current rules.  If you have
> a case where an rtx constant isn't sign-extended for the mode in which
> it's being used, then either the constant wasn't created correctly or
> the code that's calling from_rtx has got the wrong mode.  Those are bugs
> even now.
>
> This is enforced in some places already.  E.g. if an insn has a QImode
> const_int_operand, (const_int 128) will not match (assuming 8 bits
> per unit of course).
>
> I can well imagine this patch hits cases that haven't been caught
> yet though.
I agree in an ideal world, those canonization rules would be true. But i 
am a big believer in "trust but verify" and since there was no 
verification, because there is no mode actually provided, it is not 
surprising that we fail.

I am simply staking out the position that fixing this is an unreasonable 
precondition for wide-int.

> FWIW, I think the thing you mention here...
>
>> Fixing this is on Richard Sandiford's and my "it would be nice list" but
>> is certainly out of the question to do as a prereq for this patch.
> ...is the idea of attaching the mode to the constant, rather than
> having to keep track of it separately.  That's definitely still
> something I'd like to do, but it wouldn't involve any changes to
> the canonicalisation rules.
>
> I still agree that abstracting the storage seems like an unnecessary
> complication.  In the other thread, Richard B said:
>
>> The patches introduce a lot more temporary wide-ints (your words) and
>> at the same time makes construction of them from tree / rtx very expensive
>> both stack space and compile-time wise.  Look at how we for example
>> compute TREE_INT_CST + 1 - int_cst_binop internally uses double_ints
>> for the computation and then instantiates a new tree for holding the result.
>> Now we'd use wide_ints for this requring totally unnecessary copying.
> But surely the expensive part of that operation is instantiating the
> new tree, with its associated hash table lookup and potential allocation.
> Trying to save one or two copies of integers from heap to stack seems
> minor compared to that.
I have made the point that the huge number of wide ints created are 
actually very cheap because the larger than necessary space is never 
initialized and the space is on the stack and goes away very quickly.

this "enhancement" to wide int really makes no sense.   Mike i an have 
spent a lot of time going down this rat hole, and it is time to put it 
to rest.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch - patch ping for the next stage 1
  2012-10-06  0:14                                 ` patch to fix constant math - first small patch Joseph S. Myers
  2012-10-08 19:25                                   ` Kenneth Zadeck
  2012-11-08 17:37                                   ` Kenneth Zadeck
@ 2013-02-27  0:23                                   ` Kenneth Zadeck
  2013-03-27 14:13                                     ` Richard Biener
  2 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-02-27  0:23 UTC (permalink / raw)
  To: Joseph S. Myers
  Cc: Richard Guenther, Mike Stump, gcc-patches, rdsandiford,
	Ian Lance Taylor, Kenneth Zadeck

[-- Attachment #1: Type: text/plain, Size: 563 bytes --]

Here is the first of my wide int patches with joseph's comments and the 
patch rot removed.

I would like to get these pre approved for the next stage 1.
On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>
>> +# define HOST_HALF_WIDE_INT_PRINT "h"
> This may cause problems on hosts not supporting %hd (MinGW?), and there's
> no real need for using "h" here given the promotion of short to int; you
> can just use "" (rather than e.g. needing special handling in xm-mingw32.h
> like is done for HOST_LONG_LONG_FORMAT).
>


[-- Attachment #2: p1-2.clog --]
[-- Type: text/plain, Size: 389 bytes --]

2013-2-26  Kenneth Zadeck <zadeck@naturalbridge.com>

	* hwint.h (HOST_BITS_PER_HALF_WIDE_INT, HOST_HALF_WIDE_INT,
	HOST_HALF_WIDE_INT_PRINT, HOST_HALF_WIDE_INT_PRINT_C,
	HOST_HALF_WIDE_INT_PRINT_DEC, HOST_HALF_WIDE_INT_PRINT_DEC_C,
	HOST_HALF_WIDE_INT_PRINT_UNSIGNED, HOST_HALF_WIDE_INT_PRINT_HEX,
	HOST_HALF_WIDE_INT_PRINT_HEX_PURE): New symbols.
	(sext_hwi, zext_hwi): New functions.
	

[-- Attachment #3: p1-3.diff --]
[-- Type: text/x-patch, Size: 4057 bytes --]

diff --git a/gcc/hwint.h b/gcc/hwint.h
index da62fad..aaa66ed 100644
--- a/gcc/hwint.h
+++ b/gcc/hwint.h
@@ -76,6 +76,40 @@ extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1];
 # endif
 #endif
 
+/* Print support for half a host wide int.  */
+#define HOST_BITS_PER_HALF_WIDE_INT (HOST_BITS_PER_WIDE_INT / 2)
+#if HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_LONG
+# define HOST_HALF_WIDE_INT long
+# define HOST_HALF_WIDE_INT_PRINT HOST_LONG_FORMAT
+# define HOST_HALF_WIDE_INT_PRINT_C "L"
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_INT
+# define HOST_HALF_WIDE_INT int
+# define HOST_HALF_WIDE_INT_PRINT ""
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_SHORT
+# define HOST_HALF_WIDE_INT short
+# define HOST_HALF_WIDE_INT_PRINT ""
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#else
+#error Please add support for HOST_HALF_WIDE_INT
+#endif
+
+
 #define HOST_WIDE_INT_1 HOST_WIDE_INT_C(1)
 
 /* This is a magic identifier which allows GCC to figure out the type
@@ -93,9 +127,13 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
 # if HOST_BITS_PER_WIDE_INT == 64
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%016" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%016" HOST_LONG_FORMAT "x"
 # else
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%08" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%08" HOST_LONG_FORMAT "x"
 # endif
 #else
 # define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT
@@ -103,6 +141,8 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
   /* We can assume that 'long long' is at least 64 bits.  */
 # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
     "0x%" HOST_LONG_LONG_FORMAT "x%016" HOST_LONG_LONG_FORMAT "x"
+# define HOST_WIDE_INT_PRINT_PADDED_HEX \
+    "%016" HOST_LONG_LONG_FORMAT "x"
 #endif /* HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG */
 
 #define HOST_WIDE_INT_PRINT_DEC "%" HOST_WIDE_INT_PRINT "d"
@@ -276,4 +316,32 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT);
 
+/* Sign extend SRC starting from PREC.  */
+
+static inline HOST_WIDE_INT
+sext_hwi (HOST_WIDE_INT src, int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    {
+      int shift = HOST_BITS_PER_WIDE_INT - (prec & (HOST_BITS_PER_WIDE_INT - 1));
+      return (src << shift) >> shift;
+    }
+}
+
+/* Zero extend SRC starting from PREC.  */
+
+static inline HOST_WIDE_INT
+zext_hwi (HOST_WIDE_INT src, int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    return src & (((HOST_WIDE_INT)1
+		   << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
+}
+
+
+
 #endif /* ! GCC_HWINT_H */

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - second small patch -patch ping for next stage 1
  2012-10-05 22:48                                 ` patch to fix constant math - second " Kenneth Zadeck
  2012-10-06 15:55                                   ` patch to fix constant math - third " Kenneth Zadeck
  2012-10-08  9:07                                   ` patch to fix constant math - second " Richard Guenther
@ 2013-02-27  0:28                                   ` Kenneth Zadeck
  2013-03-27 14:18                                     ` Richard Biener
  2 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-02-27  0:28 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Richard Guenther, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 590 bytes --]

Here is the second of my wide int patches with the patch rot removed.

I would like to get these pre approved for the next stage 1.
On 10/05/2012 06:48 PM, Kenneth Zadeck wrote:
> This patch adds machinery to genmodes.c so that largest possible sizes 
> of various data structures can be determined at gcc build time. These 
> functions create 3 symbols that are available in insn-modes.h:
> MAX_BITSIZE_MODE_INT - the bitsize of the largest int.
> MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int.
> MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int.


[-- Attachment #2: p2-3.clog --]
[-- Type: text/plain, Size: 324 bytes --]

2013-2-26  Kenneth Zadeck <zadeck@naturalbridge.com>

   	* genmodes.c (emit_max_int): New function.
	(emit_insn_modes_h): Added call to emit_max_function.
	* doc/rtl.texi (MAX_BITSIZE_MODE_INT, MAX_BITSIZE_MODE_PARTIAL_INT,
	MAX_BITSIZE_MODE_ANY_INT, MAX_BITSIZE_MODE_ANY_MODE): Added doc.	
	* machmode.def: Fixed comment.

[-- Attachment #3: p2-3.diff --]
[-- Type: text/x-patch, Size: 3378 bytes --]

diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index b0b0723..095a642 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -1456,6 +1456,28 @@ Returns the number of units contained in a mode, i.e.,
 Returns the narrowest mode in mode class @var{c}.
 @end table
 
+The following 4 variables are defined on every target.   They can be
+used to allocate buffers that are guaranteed to be large enough to
+hold any value that can be represented on the target.   
+
+@table @code
+@findex MAX_BITSIZE_MODE_INT
+@item MAX_BITSIZE_MODE_INT
+The bitsize of the largest integer mode defined on the target.
+
+@findex MAX_BITSIZE_MODE_PARTIAL_INT
+@item MAX_BITSIZE_MODE_PARTIAL_INT
+The bitsize of the largest partial integer mode defined on the target.
+
+@findex MAX_BITSIZE_MODE_ANY_INT
+@item MAX_BITSIZE_MODE_ANY_INT
+The maximum of MAX_BITSIZE_MODE_INT and MAX_BITSIZE_MODE_PARTIAL_INT.
+
+@findex MAX_BITSIZE_MODE_ANY_MODE
+@item MAX_BITSIZE_MODE_ANY_MODE
+The bitsize of the largest mode on the target.   
+@end table
+
 @findex byte_mode
 @findex word_mode
 The global variables @code{byte_mode} and @code{word_mode} contain modes
diff --git a/gcc/genmodes.c b/gcc/genmodes.c
index 9907d69..f822dcd 100644
--- a/gcc/genmodes.c
+++ b/gcc/genmodes.c
@@ -848,6 +848,38 @@ calc_wider_mode (void)
 
 #define print_closer() puts ("};")
 
+/* Compute the max bitsize of some of the classes of integers.  It may
+   be that there are needs for the other integer classes, and this
+   code is easy to extend.  */
+static void
+emit_max_int (void)
+{
+  unsigned int max, mmax;
+  struct mode_data *i;
+  int j;
+
+  puts ("");
+  for (max = 1, i = modes[MODE_INT]; i; i = i->next)
+    if (max < i->bytesize)
+	max = i->bytesize;
+  printf ("#define MAX_BITSIZE_MODE_INT %d*BITS_PER_UNIT\n", max);
+  mmax = max;
+  for (max = 1, i = modes[MODE_PARTIAL_INT]; i; i = i->next)
+    if (max < i->bytesize)
+	max = i->bytesize;
+  printf ("#define MAX_BITSIZE_MODE_PARTIAL_INT %d*BITS_PER_UNIT\n", max);
+  if (max > mmax)
+    mmax = max;
+  printf ("#define MAX_BITSIZE_MODE_ANY_INT %d*BITS_PER_UNIT\n", mmax);
+
+  mmax = 0;
+  for (j = 0; j < MAX_MODE_CLASS; j++)
+    for (i = modes[j]; i; i = i->next)
+      if (mmax < i->bytesize)
+	mmax = i->bytesize;
+  printf ("#define MAX_BITSIZE_MODE_ANY_MODE %d*BITS_PER_UNIT\n", mmax);
+}
+
 static void
 emit_insn_modes_h (void)
 {
@@ -912,6 +944,7 @@ enum machine_mode\n{");
 #endif
   printf ("#define CONST_MODE_IBIT%s\n", adj_ibit ? "" : " const");
   printf ("#define CONST_MODE_FBIT%s\n", adj_fbit ? "" : " const");
+  emit_max_int ();
   puts ("\
 \n\
 #endif /* insn-modes.h */");
diff --git a/gcc/machmode.def b/gcc/machmode.def
index 4b58150..1062f18 100644
--- a/gcc/machmode.def
+++ b/gcc/machmode.def
@@ -179,8 +179,11 @@ RANDOM_MODE (BLK);
 FRACTIONAL_INT_MODE (BI, 1, 1);
 
 /* Basic integer modes.  We go up to TI in generic code (128 bits).
-   The name OI is reserved for a 256-bit type (needed by some back ends).
-   FIXME TI shouldn't be generically available either.  */
+   TImode is needed here because the some front ends now genericly
+   support __int128.  If the front ends decide to generically support
+   larger types, then corresponding modes must be added here.  The
+   name OI is reserved for a 256-bit type (needed by some back ends).
+    */
 INT_MODE (QI, 1);
 INT_MODE (HI, 2);
 INT_MODE (SI, 4);

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2012-10-31 14:25                                                                       ` Richard Biener
                                                                                           ` (2 preceding siblings ...)
  2012-11-30 16:46                                                                         ` patch to fix constant math - 4th patch - the wide-int class Kenneth Zadeck
@ 2013-02-27  1:59                                                                         ` Kenneth Zadeck
  2013-03-27 14:54                                                                           ` Richard Biener
  2013-04-02 15:40                                                                           ` Richard Biener
  3 siblings, 2 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-02-27  1:59 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford,
	Ian Lance Taylor, Kenneth Zadeck

[-- Attachment #1: Type: text/plain, Size: 611 bytes --]

This patch contains a large number of the changes requested by Richi.   
It does not contain any of the changes that he requested to abstract the 
storage layer.   That suggestion appears to be quite unworkable.

I believe that the wide-int class addresses the needs of gcc for 
performing math on any size integer irregardless of the platform that 
hosts the compiler.  The interface is admittedly large, but it is large 
for a reason:  these are the operations that are commonly performed by 
the client optimizations in the compiler.

I would like to get this patch preapproved for the next stage 1.

kenny


[-- Attachment #2: p4-4.diff --]
[-- Type: text/x-patch, Size: 155750 bytes --]

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index f3bb168..ce4bc93 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -852,7 +852,7 @@ COMMON_TARGET_DEF_H = common/common-target-def.h \
 RTL_BASE_H = coretypes.h rtl.h rtl.def $(MACHMODE_H) reg-notes.def \
   insn-notes.def $(INPUT_H) $(REAL_H) statistics.h $(VEC_H) \
   $(FIXED_VALUE_H) alias.h $(HASHTAB_H)
-FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h
+FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h wide-int.h
 RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h
 RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H)
 READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
@@ -864,7 +864,7 @@ INTERNAL_FN_H = internal-fn.h $(INTERNAL_FN_DEF)
 TREE_H = coretypes.h tree.h all-tree.def tree.def c-family/c-common.def \
 	$(lang_tree_files) $(MACHMODE_H) tree-check.h $(BUILTINS_DEF) \
 	$(INPUT_H) statistics.h $(VEC_H) treestruct.def $(HASHTAB_H) \
-	double-int.h alias.h $(SYMTAB_H) $(FLAGS_H) \
+	double-int.h wide-int.h alias.h $(SYMTAB_H) $(FLAGS_H) \
 	$(REAL_H) $(FIXED_VALUE_H)
 REGSET_H = regset.h $(BITMAP_H) hard-reg-set.h
 BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) \
@@ -1453,6 +1453,7 @@ OBJS = \
 	varpool.o \
 	vmsdbgout.o \
 	web.o \
+	wide-int.o \
 	xcoffout.o \
 	$(out_object_file) \
 	$(EXTRA_OBJS) \
@@ -2674,6 +2675,7 @@ targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
    tree-ssa-alias.h $(TREE_FLOW_H)
 common/common-targhooks.o : common/common-targhooks.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(INPUT_H) $(TM_H) $(COMMON_TARGET_H) common/common-targhooks.h
+wide-int.o: wide-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
 
 bversion.h: s-bversion; @true
 s-bversion: BASE-VER
@@ -3910,15 +3912,16 @@ CFLAGS-gengtype-parse.o += -DGENERATOR_FILE
 build/gengtype-parse.o: $(BCONFIG_H)
 
 gengtype-state.o build/gengtype-state.o: gengtype-state.c $(SYSTEM_H) \
-  gengtype.h errors.h double-int.h version.h $(HASHTAB_H) $(OBSTACK_H) \
-  $(XREGEX_H)
+  gengtype.h errors.h double-int.h wide-int.h version.h $(HASHTAB_H)    \
+  $(OBSTACK_H) $(XREGEX_H)
 gengtype-state.o: $(CONFIG_H)
 CFLAGS-gengtype-state.o += -DGENERATOR_FILE
 build/gengtype-state.o: $(BCONFIG_H)
+wide-int.h: $(GTM_H) insn-modes.h
 
 gengtype.o build/gengtype.o : gengtype.c $(SYSTEM_H) gengtype.h 	\
-  rtl.def insn-notes.def errors.h double-int.h version.h $(HASHTAB_H) \
-  $(OBSTACK_H) $(XREGEX_H)
+  rtl.def insn-notes.def errors.h double-int.h wide-int.h version.h     \
+  $(HASHTAB_H) $(OBSTACK_H) $(XREGEX_H)
 gengtype.o: $(CONFIG_H)
 CFLAGS-gengtype.o += -DGENERATOR_FILE
 build/gengtype.o: $(BCONFIG_H)
diff --git a/gcc/wide-int.c b/gcc/wide-int.c
new file mode 100644
index 0000000..191fb17
--- /dev/null
+++ b/gcc/wide-int.c
@@ -0,0 +1,3541 @@
+/* Operations with very long integers.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hwint.h"
+#include "wide-int.h"
+#include "rtl.h"
+#include "tree.h"
+#include "dumpfile.h"
+
+// using wide_int::;
+
+/* Debugging routines.  */
+
+/* This is the maximal size of the buffer needed for dump.  */
+const int MAX_SIZE = 4 * (MAX_BITSIZE_MODE_ANY_INT / 4
+		     + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
+
+/*
+ * Internal utilities.
+ */
+
+/* Quantities to deal with values that hold half of a wide int.  Used
+   in multiply and divide.  */
+#define HALF_INT_MASK (((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1)
+
+#define BLOCK_OF(TARGET) ((TARGET) / HOST_BITS_PER_WIDE_INT)
+#define BLOCKS_NEEDED(PREC) \
+  (((PREC) + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+
+/*
+ * Conversion routines in and out of wide-int.
+ */
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  The overflow bit are set if the number was too
+   large to fit in the mode.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, unsigned int bitsize,
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT t = sext_hwi (op0, precision);
+      if (t != op0)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+  result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wh ("wide_int::from_shwi %s " HOST_WIDE_INT_PRINT_HEX ")\n",
+	      result, op0);
+#endif
+
+  return result;
+}
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  The overflow bit are set if the number was too
+   large to fit in the mode.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, unsigned int bitsize, 
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT t = zext_hwi (op0, precision);
+      if (t != op0)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && precision > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wh ("wide_int::from_uhwi %s " HOST_WIDE_INT_PRINT_HEX ")\n",
+	      result, op0);
+#endif
+
+  return result;
+}
+
+/* Create a wide_int from an array of host_wide_ints in OP1 of LEN.
+   The result has BITSIZE and PRECISION.  */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT *op1, unsigned int len, 
+		      unsigned int bitsize, unsigned int precision)
+{
+  unsigned int i;
+  wide_int result;
+  
+  result.len = len;
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  for (i=0; i < len; i++)
+    result.val[i] = op1[i];
+
+  result.canonize ();
+  return result;
+}
+
+/* Convert a double int into a wide int with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::from_double_int (double_int di, unsigned int bs, unsigned int prec)
+{
+  HOST_WIDE_INT op = di.low;
+  wide_int result;
+
+  result.bitsize = bs;
+  result.precision = prec;
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result.val[0] = sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    result.val[1] = sext_hwi (di.high, prec);
+	  else
+	    result.val[1] = di.high;
+	}
+    }
+
+  if (result.len == 2)
+    result.canonize ();
+
+  return result;
+}
+
+/* Convert a integer cst into a wide int.  */
+
+wide_int
+wide_int::from_tree (const_tree tcst)
+{
+#ifdef NEW_REP_FOR_INT_CST
+  /* This is the code once the tree level is converted.  */
+  wide_int result;
+  int i;
+
+  tree type = TREE_TYPE (tcst);
+
+  result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  result.precision = TYPE_PRECISION (type);
+  result.len = TREE_INT_CST_LEN (tcst);
+  for (i = 0; i < result.len; i++)
+    result.val[i] = TREE_INT_CST_ELT (tcst, i);
+
+  return result;
+#else
+  wide_int result;
+  tree type = TREE_TYPE (tcst);
+  unsigned int prec = TYPE_PRECISION (type);
+  HOST_WIDE_INT op = TREE_INT_CST_LOW (tcst);
+
+  result.precision = prec;
+  result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    if (TYPE_UNSIGNED (type))
+      result.val[0] = zext_hwi (op, prec);
+    else
+      result.val[0] = sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    {
+	      op = TREE_INT_CST_HIGH (tcst);
+	      if (TYPE_UNSIGNED (type))
+		result.val[1] = zext_hwi (op, prec);
+	      else
+		result.val[1] = sext_hwi (op, prec);
+	    }
+	  else
+	    result.val[1] = TREE_INT_CST_HIGH (tcst);
+	}
+      else
+	result.len = 1;
+    }
+  
+  if (result.len == 2)
+    result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      debug_whh ("wide_int:: %s = from_tree ("HOST_WIDE_INT_PRINT_HEX" "HOST_WIDE_INT_PRINT_HEX")\n",
+		 result, TREE_INT_CST_HIGH (tcst), TREE_INT_CST_LOW (tcst));
+    }
+#endif
+
+  return result;
+#endif
+}
+
+/* Convert a integer cst into a wide int expanded to BITSIZE and
+   PRECISION.  This call is used by tree passes like vrp that expect
+   that the math is done in an infinite precision style.  BITSIZE and
+   PRECISION are generally determined to be twice the largest type
+   seen in the function.  */
+
+wide_int
+wide_int::from_tree_as_infinite_precision (const_tree tcst, 
+					   unsigned int bitsize, 
+					   unsigned int precision)
+{
+  /* The plan here is to extend the value in the cst, using signed or
+     unsigned based on the type, from the precision in the type to
+     PRECISION and then canonize from there.  */
+  wide_int result;
+  tree type = TREE_TYPE (tcst);
+  unsigned int prec = TYPE_PRECISION (type);
+
+
+#ifdef NEW_REP_FOR_INT_CST
+  /* This is the code once the tree level is converted.  */
+  int i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  result.len = TREE_INT_CST_LEN (tcst);
+  for (i = 0; i < result.len; i++)
+    result.val[i] = TREE_INT_CST_ELT (tcst, i);
+
+  if (TYPE_UNSIGNED (type))
+    result = result.zext (prec);
+  else
+    result = result.sext (prec);
+
+#else
+  HOST_WIDE_INT op = TREE_INT_CST_LOW (tcst);
+
+  gcc_assert (prec <= precision);
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  result.len = 1;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result.val[0] = TYPE_UNSIGNED (type) 
+      ? zext_hwi (op, prec) : sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    {
+	      op = TREE_INT_CST_HIGH (tcst);
+	      prec -= HOST_BITS_PER_WIDE_INT;
+	      result.val[1] = TYPE_UNSIGNED (type) 
+		? zext_hwi (op, prec) : sext_hwi (op, prec);
+	      result.len = 2;
+	    }
+	  else
+	    {
+	      result.val[1] = TREE_INT_CST_HIGH (tcst);
+	      if (TYPE_UNSIGNED (type) && result.val[1] < 0)
+		{
+		  result.val[2] = 0;
+		  result.len = 2;
+		}
+	      else
+		result.len = 2;
+	    }
+	}
+      else
+	if (TYPE_UNSIGNED (type) && result.val[0] < 0)
+	  {
+	    result.val[1] = 0;
+	    result.len = 2;
+	  }
+    }
+
+#endif
+
+  return result;
+}
+
+/* Extract a constant integer from the X of type MODE.  The bits of
+   the integer are returned.  */
+
+wide_int
+wide_int::from_rtx (const_rtx x, enum machine_mode mode)
+{
+  wide_int result;
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  gcc_assert (mode != VOIDmode);
+
+  result.bitsize = GET_MODE_BITSIZE (mode);
+  result.precision = prec;
+
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+      if ((prec & (HOST_BITS_PER_WIDE_INT - 1)) != 0)
+	result.val[0] = sext_hwi (INTVAL (x), prec);
+      else
+	result.val[0] = INTVAL (x);
+      result.len = 1;
+      break;
+
+#if TARGET_SUPPORTS_WIDE_INT
+    case CONST_WIDE_INT:
+      {
+	int i;
+	result.len = CONST_WIDE_INT_NUNITS (x);
+	
+	for (i = 0; i < result.len; i++)
+	  result.val[i] = CONST_WIDE_INT_ELT (x, i);
+      }
+      break;
+#else
+    case CONST_DOUBLE:
+      result.len = 2;
+      result.val[0] = CONST_DOUBLE_LOW (x);
+      result.val[1] = CONST_DOUBLE_HIGH (x);
+      result.canonize ();
+      break;
+#endif
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return result;
+}
+
+/*
+ * Largest and smallest values in a mode.
+ */
+
+/* Produce the largest SGNed number that is represented in PREC.  The
+   resulting number is placed in a wide int of size BITSIZE and
+   PRECISION.  */
+
+wide_int
+wide_int::max_value (unsigned int prec, 
+		     unsigned int bitsize, unsigned int precision, 
+		     SignOp sgn)
+{
+  wide_int result;
+  
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned max is just all ones, for which the compressed
+	 rep is just a single HWI.  */ 
+      result.len = 1;
+      result.val[0] = (HOST_WIDE_INT)-1;
+    }
+  else
+    {
+      /* The signed max is all ones except the top bit.  This must be
+	 explicitly represented.  */
+      int i;
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      int shift = (small_prec == 0) 
+	? HOST_BITS_PER_WIDE_INT - 1 : small_prec - 1;
+
+      result.len = BLOCKS_NEEDED (prec);
+      for (i = 0; i < result.len - 1; i++)
+	result.val[i] = (HOST_WIDE_INT)-1;
+
+      result.val[result.len - 1] = ((HOST_WIDE_INT)1 << shift) - 1;
+    }
+  
+  return result;
+}
+
+/* Produce the smallest SGNed number that is represented in PREC.  The
+   resulting number is placed in a wide int of size BITSIZE and
+   PRECISION.  */
+
+wide_int
+wide_int::min_value (unsigned int prec, 
+		     unsigned int bitsize, unsigned int precision, 
+		     SignOp sgn)
+{
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned min is just all zeros, for which the compressed
+	 rep is just a single HWI.  */ 
+      wide_int result;
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = 0;
+      return result;
+    }
+  else
+    {
+      /* The signed min is all zeros except the top bit.  This must be
+	 explicitly represented.  */
+      return set_bit_in_zero (prec - 1, bitsize, precision);
+    }
+}
+
+/*
+ * Public utilities.
+ */
+
+/* Check the upper HOST_WIDE_INTs of src to see if the length can be
+   shortened.  An upper HOST_WIDE_INT is unnecessary if it is all ones
+   or zeros and the top bit of the next lower word matches.
+
+   This function may change the representation of THIS, but does not
+   change the value that THIS represents.  It does not sign extend in
+   the case that the size of the mode is less than
+   HOST_BITS_PER_WIDE_INT.  */
+
+void
+wide_int::canonize ()
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT top;
+  int i;
+
+  if (len > blocks_needed)
+    len = blocks_needed;
+
+  /* Clean up the top bits for any mode that is not a multiple of a HWI.  */
+  if (len == blocks_needed && small_prec)
+    val[len - 1] = sext_hwi (val[len - 1], small_prec);
+
+  if (len == 1)
+    return;
+
+  top = val[len - 1];
+  if (top != 0 && top != (HOST_WIDE_INT)-1)
+    return;
+
+  /* At this point we know that the top is either 0 or -1.  Find the
+     first block that is not a copy of this.  */
+  for (i = len - 2; i >= 0; i--)
+    {
+      HOST_WIDE_INT x = val[i];
+      if (x != top)
+	{
+	  if (x >> (HOST_BITS_PER_WIDE_INT - 1) == top)
+	    {
+	      len = i + 1;
+	      return;
+	    }
+
+	  /* We need an extra block because the top bit block i does
+	     not match the extension.  */
+	  len = i + 2;
+	  return;
+	}
+    }
+
+  /* The number is 0 or -1.  */
+  len = 1;
+}
+
+
+/* Make a copy of this.  */
+
+wide_int
+wide_int::copy () const
+{
+  wide_int result;
+  int i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+  return result;
+}
+
+
+/* Copy THIS replacing the bitsize with BS and precision with PREC.
+   It can do any of truncation, extension or copying.  */
+
+wide_int
+wide_int::force_to_size (unsigned int bs, unsigned int prec, SignOp sgn) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (prec);
+  int i;
+
+  result.bitsize = bs;
+  result.precision = prec;
+  result.len = blocks_needed < len ? blocks_needed : len;
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+
+  if (prec >= precision) 
+    {
+      /* Expanding */
+      int small_precision = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+      if (sgn == UNSIGNED)
+	{
+	  if (len == BLOCKS_NEEDED (precision)
+	      && len < blocks_needed
+	      && small_precision == 0
+	      && result.val[result.len - 1] < 0)
+	    /* We need to put the 0 block on top to keep the value
+	       from being sign extended.  */ 
+	    result.val[result.len++] = 0;
+	  /* We are unsigned and the current precision is not on an
+	     even block and that block is explicitly represented.
+	     Then we have to do an explicit zext of the top block. */
+	  else if (small_precision && blocks_needed == len)
+	    result.val[blocks_needed-1]
+	      = zext_hwi (result.val[blocks_needed-1], small_precision);
+	}
+    }
+  else
+    {
+      /* Truncating.  */
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      /* The only weird case we need to look at here is when we are
+         truncating within the top block.  We need to make sure that
+         everything in the block above the new precision is sign
+         extended.  Note that this is independent of the SGN.  This is
+         just to stay canonical.  */
+      if (small_prec && (blocks_needed == len))
+	result.val[blocks_needed-1]
+	  = sext_hwi (result.val[blocks_needed-1], small_prec);
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwvvs ("wide_int:: %s = force_to_size (%s, bs = %d, prec = %d %s)\n", 
+		 result, *this, bs, prec, sgn==UNSIGNED ? "U" : "S");
+#endif
+
+  return result;
+}
+
+/*
+ * public printing routines.
+ */
+
+/* Try to print the signed self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_DEC, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decs (buf);
+  fputs (buf, file);
+}
+
+/* Try to print the unsigned self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decu (buf);
+  fputs (buf, file);
+}
+
+void 
+wide_int::print_hex (char *buf) const
+{
+  int i = len;
+
+  if (zero_p ())
+    sprintf (buf, "0x");
+  else
+    {
+      if (neg_p ())
+	{
+	  int j;
+	  /* If the number is negative, we may need to pad value with
+	     0xFFF...  because the leading elements may be missing and
+	     we do not print a '-' with hex.  */
+	  for (j = BLOCKS_NEEDED (precision); j > i; j--)
+	    buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, (HOST_WIDE_INT) -1);
+	    
+	}
+      else
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_HEX, val [--i]);
+      while (-- i >= 0)
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, val [i]);
+    }
+}
+
+/* Print one big hex number to FILE.  Note that some assemblers may not
+   accept this for large modes.  */
+void 
+wide_int::print_hex (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_hex (buf);
+  fputs (buf, file);
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently singed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+bool
+wide_int::eq_p_large (const wide_int &op1) const
+{
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  while (l0 > l1)
+    if (val[l0--] != op1.sign_mask ())
+      return false;
+
+  while (l1 > l0)
+    if (op1.val[l1--] != sign_mask ())
+      return false;
+
+  while (l0 >= 0)
+    if (val[l0--] != op1.val[l1--])
+      return false;
+
+  return true;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p_large (const wide_int &op1) const
+{
+  int l;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  int blocks_needed = BLOCKS_NEEDED (precision);
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == len ? val [blocks_needed - 1] : sign_mask ();
+  s1 = blocks_needed == op1.len ? op1.val [blocks_needed - 1] : op1.sign_mask ();
+  if (s0 < s1)
+    return true;
+  if (s0 > s1)
+    return false;
+
+  l = MAX (len, op1.len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < len ? val [l] : sign_mask ();
+      u1 = l < op1.len ? op1.val [l] : op1.sign_mask ();
+
+      if (u0 < u1)
+	return true;
+      if (u0 > u1)
+	return false;
+      l--;
+    }
+
+  return false;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+int
+wide_int::cmps_large (const wide_int &op1) const
+{
+  int l;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  int blocks_needed = BLOCKS_NEEDED (precision);
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == len ? val [blocks_needed - 1] : sign_mask ();
+  s1 = blocks_needed == op1.len ? op1.val [blocks_needed - 1] : op1.sign_mask ();
+  if (s0 < s1)
+    return -1;
+  if (s0 > s1)
+    return 1;
+
+  l = MAX (len, op1.len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < len ? val [l] : sign_mask ();
+      u1 = l < op1.len ? op1.val [l] : op1.sign_mask ();
+
+      if (u0 < u1)
+	return -1;
+      if (u0 > u1)
+	return 1;
+      l--;
+    }
+
+  return 0;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p_large (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1.sign_mask ();
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  while (l1 > l0)
+    {
+      x0 = sign_mask ();
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  return false;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+int
+wide_int::cmpu_large (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1.sign_mask ();
+      if (x0 < x1)
+	return -1;
+      else if (x0 > x1)
+	return 1;
+    }
+
+  while (l1 > l0)
+    {
+      x0 = sign_mask ();
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	return -1;
+      if (x0 > x1)
+	return 1;
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	return -1;
+      if (x0 > x1)
+	return 1;
+    }
+
+  return 0;
+}
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p (unsigned int prec) const
+{
+  int i;
+  HOST_WIDE_INT x;
+  int small_prec;
+  bool result;
+
+  if (BLOCKS_NEEDED (prec) != len)
+    {
+      result = false;
+      goto ex;
+    }
+
+  for (i=0; i < len - 1; i++)
+    if (val[i] != 0)
+      {
+	result = false;
+	goto ex;
+      }
+
+  x = val[len - 1];
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec)
+    x = x << (HOST_BITS_PER_WIDE_INT - small_prec);
+
+  result = x == ((HOST_WIDE_INT)1) << (HOST_BITS_PER_WIDE_INT - 1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = only_sign_bit_p (%s)\n", result, *this);
+#endif
+
+  return result;
+}
+
+/* Returns true if THIS fits into range of TYPE.  Signedness of OP0 is
+   assumed to be the same as the signedness of TYPE.  */
+
+bool
+wide_int::fits_to_tree_p (const_tree type) const
+{
+  int type_prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return fits_u_p (type_prec);
+  else
+    return fits_s_p (type_prec);
+}
+
+/* Returns true of THIS fits in the unsigned range of precision.  */
+
+bool
+wide_int::fits_s_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == sext (prec);
+}
+
+
+/* Returns true if THIS fits into range of TYPE.  */
+
+bool
+wide_int::fits_u_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == zext (prec);
+}
+
+/*
+ * Extension.
+ */
+
+/* Sign extend THIS starting at OFFSET.  The bitsize and precision of
+   the result are the same as THIS.  */
+
+wide_int
+wide_int::sext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.bitsize = bitsize;
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = sext_hwi (val[0], offset);
+      else
+	/* If offset is greater or equal to precision there is nothing
+	   to do since the internal rep is already sign extended.  */
+	result.val[0] = val[0];
+
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, bitsize, precision);
+      
+      /* Now we can do the real sign extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      if (off)
+	{
+	  int block = BLOCK_OF (offset);
+	  result.val[block] = sext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      /* We never need an extra element for sign extended values.  */
+    }    
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s sext %d)\n", result, *this, offset);
+#endif
+
+  return result;
+}
+
+/* Zero extend THIS starting at OFFSET.  The bitsize and precision of
+   the result are the same as THIS.  */
+
+wide_int
+wide_int::zext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+  int block;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.bitsize = bitsize;
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = zext_hwi (val[0], offset);
+      else if (offset == precision)
+	result.val[0] = val[0];
+	/* If offset was greater than the precision we need to zero
+	   extend from the old precision since the internal rep was
+	   equivalent to sign extended.  */
+      else
+	result.val[0] = zext_hwi (val[0], precision);
+	
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, bitsize, precision);
+
+      /* Now we can do the real zero extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      block = BLOCK_OF (offset);
+      if (off)
+	{
+	  result.val[block] = zext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      else
+	/* See if we need an extra zero element to satisfy the
+	   compression rule.  */
+	if (val[block - 1] < 0 && offset < precision)
+	  {
+	    result.val[block] = 0;
+	    result.len += 1;
+	  }
+    }
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s zext %d)\n", result, *this, offset);
+#endif
+
+  return result;
+}
+
+/*
+ * Masking, inserting, shifting, rotating.
+ */
+
+/* Return a value with a one bit inserted in THIS at BITPOS.  */
+
+wide_int
+wide_int::set_bit (unsigned int bitpos) const
+{
+  wide_int result;
+  int i, j;
+
+  if (bitpos >= precision)
+    result = copy ();
+  else
+    {
+      result = decompress (bitpos, bitsize, precision);
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s set_bit %d)\n", result, *this, bitpos);
+#endif
+
+  return result;
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with BITSIZE
+   and PRECISION.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, 
+			   unsigned int bitsize, unsigned int prec)
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (bitpos + 1);
+  int i, j;
+
+  result.bitsize = bitsize;
+  result.precision = prec;
+  if (bitpos >= prec)
+    {
+      result.len = 1;
+      result.val[0] = 0;
+    }
+  else
+    {
+      result.len = blocks_needed;
+      for (i = 0; i < blocks_needed; i++)
+	result.val[i] = 0;
+      
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wv ("wide_int:: %s = set_bit_in_zero (%d)\n", result, bitpos);
+#endif
+
+  return result;
+}
+
+/* Insert WIDTH bits from OP0 into THIS starting at START.  */
+
+wide_int
+wide_int::insert (const wide_int &op0, unsigned int start, 
+		  unsigned int width) const
+{
+  wide_int result;
+  wide_int mask;
+  wide_int tmp;
+
+  if (start + width >= precision) 
+    width = precision - start;
+
+  mask = shifted_mask (start, width, false, bitsize, precision);
+  tmp = op0.lshift (start, NONE, bitsize, precision);
+  result = tmp & mask;
+
+  tmp = and_not (mask);
+  result = result | tmp;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwwvv ("wide_int:: %s = (%s insert start = %d width = %d)\n", 
+		 result, *this, op0, start, width);
+#endif
+
+  return result;
+}
+
+/* bswap THIS.  */
+
+wide_int
+wide_int::bswap () const
+{
+  wide_int result;
+  int i, s;
+  int end;
+  int len = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT mask = sign_mask ();
+
+  /* This is not a well defined operation if the precision is not a
+     multiple of 8.  */
+  gcc_assert ((precision & 0x7) == 0);
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < len; i++)
+    result.val[0] = mask;
+
+  /* Only swap the bytes that are not the padding.  */
+  if ((precision & (HOST_BITS_PER_WIDE_INT - 1))
+      && (this->len == len))
+    end = precision;
+  else
+    end = this->len * HOST_BITS_PER_WIDE_INT;
+
+  for (s = 0; s < end; s += 8)
+    {
+      unsigned int d = precision - s - 8;
+      unsigned HOST_WIDE_INT byte;
+
+      int block = s / HOST_BITS_PER_WIDE_INT;
+      int offset = s & (HOST_BITS_PER_WIDE_INT - 1);
+
+      byte = (val[block] >> offset) & 0xff;
+
+      block = d / HOST_BITS_PER_WIDE_INT;
+      offset = d & (HOST_BITS_PER_WIDE_INT - 1);
+
+      result.val[block] &= ((((HOST_WIDE_INT)1 << offset) + 8)
+			    - ((HOST_WIDE_INT)1 << offset));
+      result.val[block] |= byte << offset;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = bswap (%s)\n", result, *this);
+#endif
+
+  return result;
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with BITSIZE and
+   PREC. */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, 
+		unsigned int bitsize, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  int shift;
+
+  gcc_assert (width < 2 * MAX_BITSIZE_MODE_ANY_INT);
+  gcc_assert (prec <= 2 * MAX_BITSIZE_MODE_ANY_INT);
+
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (bitsize, prec);
+      else
+	result = wide_int::zero (bitsize, prec);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wvv ("wide_int:: %s = mask (%d, negate = %d)\n", result, width, negate);
+#endif
+      return result;
+    }
+
+  result.bitsize = bitsize;
+  result.precision = prec;
+
+  while (i < width / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = width & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      HOST_WIDE_INT last = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~last : last;
+    }
+  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvv ("wide_int:: %s = mask (%d, negate = %d)\n", result, width, negate);
+#endif
+
+  return result;
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  */
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate,
+			unsigned int bitsize, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  unsigned int shift;
+  unsigned int end = start + width;
+  HOST_WIDE_INT block;
+
+  if (start + width > prec)
+    width = prec - start;
+ 
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (bitsize, prec);
+      else
+	result = wide_int::zero (bitsize, prec);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wvvv 
+	  ("wide_int:: %s = shifted_mask (start = %d width = %d negate = %d)\n", 
+	   result, start, width, negate);
+#endif
+      return result;
+    }
+
+  result.bitsize = bitsize;
+  result.precision = prec;
+
+  while (i < start / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? (HOST_WIDE_INT)-1 : 0;
+
+  shift = start & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift)
+    {
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      shift = (end) & (HOST_BITS_PER_WIDE_INT - 1);
+      if (shift)
+	{
+	  /* case 000111000 */
+	  block = (((HOST_WIDE_INT)1) << shift) - block - 1;
+	  result.val[i++] = negate ? ~block : block;
+	  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_wvvv 
+	      ("wide_int:: %s = shifted_mask (start = %d width = %d negate = %d)\n", 
+	       result, start, width, negate);
+#endif
+	  return result;
+	}
+      else
+	/* ...111000 */
+	result.val[i++] = negate ? block : ~block;
+    }
+
+  while (i < end / HOST_BITS_PER_WIDE_INT)
+    /* 1111111 */
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = end & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      /* 000011111 */
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~block : block;
+    }
+
+  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvvv 
+      ("wide_int:: %s = shifted_mask (start = %d width = %d negate = %d)\n", 
+       result, start, width, negate);
+#endif
+
+  return result;
+}
+
+
+/*
+ * logical operations.
+ */
+
+/* Return THIS & OP1.  */
+
+wide_int
+wide_int::and_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Return THIS & ~OP1.  */
+
+wide_int
+wide_int::and_not_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & ~op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+wide_int
+wide_int::or_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+  return result;
+}
+
+/* Return THIS | ~OP1.  */
+
+wide_int
+wide_int::or_not_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | ~op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Return the exclusive ior (xor) of THIS and OP1.  */
+
+wide_int
+wide_int::xor_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  result.len = MAX (len, op1.len);
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  while (l0 > l1)
+    {
+      result.val[l0] = val[l0] ^ op1.sign_mask ();
+      l0--;
+    }
+
+  while (l1 > l0)
+    {
+      result.val[l1] = sign_mask () ^ op1.val[l1];
+      l1--;
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] ^ op1.val[l0];
+      l0--;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s ^ %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/*
+ * math
+ */
+
+/* Absolute value of THIS.  */
+
+wide_int
+wide_int::abs () const
+{
+  if (sign_mask ())
+    return neg ();
+
+  wide_int result = copy ();
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = abs (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Add of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::add_large (const wide_int &op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1.len ? (unsigned HOST_WIDE_INT)op1.val[i] : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 + mask1 + carry;
+      result.len++;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/* Add of OP0 and OP1 with overflow checking.  If the result overflows
+   within the precision, set OVERFLOW.  OVERFLOW is assumed to be
+   sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::add (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT old_carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int i, small_prec;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < len; i++)
+    {
+      o0 = val[i];
+      o1 = op1.val[i];
+      x = o0 + o1 + carry;
+      result.val [i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+
+  /* Uncompress the rest.  */
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = val[i];
+      o1 = mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = mask0;
+      o1 = op1.val[i];
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 + mask1 + carry;
+      result.len++;
+      /* If we were short, we could not have overflowed.  */
+      goto ex;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (sgn == wide_int::SIGNED)
+	{
+	  if (((!(o0 ^ o1)) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
+	    *overflow = true;
+	}
+      else if (old_carry)
+	{
+	  if ((~o0) <= o1)
+	    *overflow = true;
+	}
+      else
+	{
+	  if ((~o0) < o1)
+	    *overflow = true;
+	}
+    }
+  else
+    {
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  If there are any non zero bits above the prec,
+	     we overflowed. */
+	  o0 = zext_hwi (o0, small_prec);
+	  o1 = zext_hwi (o1, small_prec);
+	  x = o0 + o1 + old_carry;
+	  if (x >> small_prec)
+	    *overflow = true;
+	}
+      else 
+	{
+	  /* Overflow in this case is easy since we can see bits beyond
+	     the precision.  If the value computed is not the sign
+	     extended value, then we have overflow.  */
+	  unsigned HOST_WIDE_INT y = sext_hwi (x, small_prec);
+	  if (x != y)
+	    *overflow = true;
+	}
+    }
+
+ ex:
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvww ("wide_int:: %s %d = (%s +O %s)\n", 
+	       result, *overflow, *this, op1);
+#endif
+  return result;
+}
+
+/* Count leading zeros of THIS but only looking at the bits in the
+   smallest HWI of size mode.  */
+
+wide_int
+wide_int::clz (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (clz (), bs, prec);
+}
+
+/* Count leading zeros of THIS.  */
+
+int
+wide_int::clz () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_vw ("wide_int:: %d = clz (%s)\n", count, *this);
+#endif
+      return count;
+    }
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = clz_hwi (v) - (HOST_BITS_PER_WIDE_INT - small_prec);
+      start = len - 2;
+      if (v != 0)
+	{
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_vw ("wide_int:: %d = clz (%s)\n", count, *this);
+#endif
+	  return count;
+	}
+    }
+  else
+    {
+      count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = elt (i);
+      count += clz_hwi (v);
+      if (v != 0)
+	break;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = clz (%s)\n", count, *this);
+#endif
+  return count;
+}
+
+wide_int
+wide_int::clrsb (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (clrsb (), bs, prec);
+}
+
+/* Count the number of redundant leading bits of THIS.  Return result
+   as a HOST_WIDE_INT.  There is a wrapper to convert this into a
+   wide_int.  */
+
+int
+wide_int::clrsb () const
+{
+  if (neg_p ())
+    return operator ~ ().clz () - 1;
+
+  return clz () - 1;
+}
+
+wide_int
+wide_int::ctz (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (ctz (), bs, prec);
+}
+
+/* Count zeros of THIS.  Return result as a HOST_WIDE_INT.  There is a
+   wrapper to convert this into a wide_int.  */
+
+int
+wide_int::ctz () const
+{
+  int i;
+  unsigned int count = 0;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int end;
+  bool more_to_do;
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_vw ("wide_int:: %d = ctz (%s)\n", count, *this);
+#endif
+      return count;
+    }
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      end = len - 1;
+      more_to_do = true;
+    }
+  else
+    {
+      end = len;
+      more_to_do = false;
+    }
+
+  for (i = 0; i < end; i++)
+    {
+      v = val[i];
+      count += ctz_hwi (v);
+      if (v != 0)
+	{
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_vw ("wide_int:: %d = ctz (%s)\n", count, *this);
+#endif
+	  return count;
+	}
+    }
+
+  if (more_to_do)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = ctz_hwi (v);
+      /* The top word was all zeros so we have to cut it back to prec,
+	 because we are counting some of the zeros above the
+	 interesting part.  */
+      if (count > precision)
+	count = precision;
+    }
+  else
+    /* Skip over the blocks that are not represented.  They must be
+       all zeros at this point.  */
+    count = precision;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = ctz (%s)\n", count, *this);
+#endif
+  return count;
+}
+
+/* ffs of THIS.  */
+
+wide_int
+wide_int::ffs () const
+{
+  HOST_WIDE_INT count = ctz ();
+  if (count == precision)
+    count = 0;
+  else
+    count += 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = ffs (%s)\n", count, *this);
+#endif
+  return wide_int::from_shwi (count, word_mode);
+}
+
+/* Subroutines of the multiplication and division operations.  Unpack
+   the first IN_LEN HOST_WIDE_INTs in INPUT into 2 * IN_LEN
+   HOST_HALF_WIDE_INTs of RESULT.  The rest of RESULT is filled by
+   uncompressing the top bit of INPUT[IN_LEN - 1].  */
+
+static void
+wi_unpack (unsigned HOST_HALF_WIDE_INT *result, 
+	   const unsigned HOST_WIDE_INT *input,
+	   int in_len, int out_len)
+{
+  int i;
+  int j = 0;
+  HOST_WIDE_INT mask;
+
+  for (i = 0; i <in_len; i++)
+    {
+      result[j++] = input[i];
+      result[j++] = input[i] >> HOST_BITS_PER_HALF_WIDE_INT;
+    }
+  mask = ((HOST_WIDE_INT)input[in_len - 1]) >> (HOST_BITS_PER_WIDE_INT - 1);
+  mask &= HALF_INT_MASK;
+
+  /* Smear the sign bit.  */
+  while (j < out_len)
+    result[j++] = mask;
+}
+
+/* The inverse of wi_unpack.  IN_LEN is the the number of input
+   blocks.  The number of output blocks will be half this amount.  */
+
+static void
+wi_pack (unsigned HOST_WIDE_INT *result, 
+	 const unsigned HOST_HALF_WIDE_INT *input, 
+	 int in_len)
+{
+  int i = 0;
+  int j = 0;
+
+  while (i < in_len - 2)
+    {
+      result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+	| ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+      i += 2;
+    }
+
+  /* Handle the case where in_len is odd.   For this we zero extend.  */
+  if (i & 1)
+    result[j++] = (unsigned HOST_WIDE_INT)input[i];
+  else
+    result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+      | ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+}
+
+/* Return an integer that is the exact log2 of THIS.  */
+
+int
+wide_int::exact_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  HOST_WIDE_INT count;
+  HOST_WIDE_INT result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec)
+	v = zext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = ::exact_log2 (v);
+      goto ex;
+    }
+
+  count = ctz ();
+  if (clz () + count + 1 == precision)
+    {
+      result = count;
+      goto ex;
+    }
+
+  result = -1;
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = exact_log2 (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Return an integer that is the floor log2 of THIS.  */
+
+int
+wide_int::floor_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  HOST_WIDE_INT result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec)
+	v = zext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = ::floor_log2 (v);
+      goto ex;
+    }
+
+  result = precision - 1 - clz ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = floor_log2 (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+
+/* Multiply Op1 by Op2.  If HIGH is set, only the upper half of the
+   result is returned.  If FULL is set, the entire result is returned
+   in a mode that is twice the width of the inputs.  However, that
+   mode needs to exist if the value is to be usable.  Clients that use
+   FULL need to check for this.
+
+   If HIGH or FULL are not setm throw away the upper half after the check
+   is made to see if it overflows.  Unfortunately there is no better
+   way to check for overflow than to do this.  OVERFLOW is assumed to
+   be sticky so it should be initialized.  SGN controls the signess
+   and is used to check overflow or if HIGH or FULL is set.  */
+
+wide_int
+wide_int::mul_internal (bool high, bool full, 
+			const wide_int *op1, const wide_int *op2,
+			wide_int::SignOp sgn,  bool *overflow, 
+			bool needs_overflow)
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1, k, t;
+  unsigned int i;
+  unsigned int j;
+  unsigned int prec = op1->get_precision ();
+  unsigned int blocks_needed = BLOCKS_NEEDED (prec);
+  unsigned int half_blocks_needed = blocks_needed * 2;
+  /* The sizes here are scaled to support a 2x largest mode by 2x
+     largest mode yielding a 4x largest mode result.  This is what is
+     needed by vpn.  */
+
+  unsigned HOST_HALF_WIDE_INT 
+    u[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT 
+    v[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  /* The '2' in 'R' is because we are internally doing a full
+     multiply.  */
+  unsigned HOST_HALF_WIDE_INT 
+    r[2 * 2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1;
+
+  result.bitsize = op1->bitsize;
+  result.precision = op1->precision;
+
+  if (high || full || needs_overflow)
+    {
+      /* If we need to check for overflow, we can only do half wide
+	 multiplies quickly because we need to look at the top bits to
+	 check for the overflow.  */
+      if (prec <= HOST_BITS_PER_HALF_WIDE_INT)
+	{
+	  HOST_WIDE_INT t, r;
+	  result.len = 1;
+	  o0 = op1->elt (0);
+	  o1 = op2->elt (0);
+	  r = o0 * o1;
+	  /* Signed shift down will leave 0 or -1 if there was no
+	     overflow for signed or 0 for unsigned.  */
+	  t = r >> (HOST_BITS_PER_HALF_WIDE_INT - 1);
+	  if (needs_overflow)
+	    {
+	      if (sgn == wide_int::SIGNED)
+		{
+		  if (t != (HOST_WIDE_INT)-1 && t != 0)
+		    *overflow = true;
+		}
+	      else
+		{
+		  if (t != 0)
+		    *overflow = true;
+		}
+	    }
+	  if (full)
+	    {
+	      result.val[0] = sext_hwi (r, prec * 2);
+	      result.bitsize = op1->bitsize * 2;
+	      result.precision = op1->precision * 2;
+	    }
+	  else if (high)
+	    result.val[0] = r >> prec;
+	  else
+	    result.val[0] = sext_hwi (r, prec);
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_wvww ("wide_int:: %s %d = (%s *O %s)\n", 
+			result, *overflow, *op1, *op2);
+#endif
+	  return result;
+	}
+    }
+
+  wi_unpack (u, (const unsigned HOST_WIDE_INT*)op1->val, op1->len,
+	     half_blocks_needed);
+  wi_unpack (v, (const unsigned HOST_WIDE_INT*)op2->val, op2->len,
+	     half_blocks_needed);
+
+  /* The 2 is for a full mult.  */
+  memset (r, 0, half_blocks_needed * 2 
+	  * HOST_BITS_PER_HALF_WIDE_INT / BITS_PER_UNIT);
+
+  for (j = 0; j < half_blocks_needed; j++)
+    {
+      k = 0;
+      for (i = 0; i < half_blocks_needed; i++)
+	{
+	  t = ((unsigned HOST_WIDE_INT)u[i] * (unsigned HOST_WIDE_INT)v[j]
+	       + r[i + j] + k);
+	  r[i + j] = t & HALF_INT_MASK;
+	  k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	}
+      r[j + half_blocks_needed] = k;
+    }
+
+  /* We did unsigned math above.  For signed we must adjust the
+     product (assuming we need to see that).  */
+  if (sgn == wide_int::SIGNED && (full || high || needs_overflow))
+    {
+      unsigned HOST_WIDE_INT b;
+      if ((*op1).neg_p ())
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)v[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+      if ((*op2).neg_p ())
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)u[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+    }
+
+  if (needs_overflow)
+    {
+      HOST_WIDE_INT top;
+
+      /* For unsigned, overflow is true if any of the top bits are set.
+	 For signed, overflow is true if any of the top bits are not equal
+	 to the sign bit.  */
+      if (sgn == wide_int::UNSIGNED)
+	top = 0;
+      else
+	{
+	  top = r[(half_blocks_needed) - 1];
+	  top = ((top << (HOST_BITS_PER_WIDE_INT / 2))
+		 >> (HOST_BITS_PER_WIDE_INT - 1));
+	  top &= mask;
+	}
+      
+      for (i = half_blocks_needed; i < half_blocks_needed * 2; i++)
+	if (((HOST_WIDE_INT)(r[i] & mask)) != top)
+	  *overflow = true; 
+    }
+
+  if (full)
+    {
+      /* compute [2prec] <- [prec] * [prec] */
+      wi_pack ((unsigned HOST_WIDE_INT*)result.val, r, 2 * half_blocks_needed);
+      result.len = blocks_needed * 2;
+      result.bitsize = op1->bitsize * 2;
+      result.precision = op1->precision * 2;
+    }
+  else if (high)
+    {
+      /* compute [prec] <- ([prec] * [prec]) >> [prec] */
+      wi_pack ((unsigned HOST_WIDE_INT*)&result.val [blocks_needed >> 1],
+	       r, half_blocks_needed);
+      result.len = blocks_needed;
+    }
+  else
+    {
+      /* compute [prec] <- ([prec] * [prec]) && ((1 << [prec]) - 1) */
+      wi_pack ((unsigned HOST_WIDE_INT*)result.val, r, half_blocks_needed);
+      result.len = blocks_needed;
+    }
+      
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvww ("wide_int:: %s %d = (%s *O %s)\n", 
+		result, *overflow, *op1, *op2);
+#endif
+  return result;
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.
+   OVERFLOW is set true if the result overflows.  */
+
+wide_int 
+wide_int::mul (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  return mul_internal (false, false, this, &op1, sgn, overflow, true);
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.  The
+   result is twice the precision as the operands.  The signess is
+   specified with SGN.  */
+
+wide_int
+wide_int::mul_full (const wide_int &op1, SignOp sgn) const
+{
+  bool overflow = false;
+
+  return mul_internal (false, true, this, &op1, sgn, &overflow, false);
+}
+
+/* Multiply THIS and OP1 and return the high part of that result.  The
+   signess is specified with SGN.  The result is the same precision as
+   the operands.  The mode is the same mode as the operands.  The
+   signess is specified with y.  */
+
+wide_int
+wide_int::mul_high (const wide_int &op1, SignOp sgn) const
+{
+  bool overflow = false;
+
+  return mul_internal (true, false, this, &op1, sgn, &overflow, false);
+}
+
+/* Compute the parity of THIS.  */
+
+wide_int
+wide_int::parity (unsigned int bs, unsigned int prec) const
+{
+  int count = popcount ();
+  return wide_int::from_shwi (count & 1, bs, prec);
+}
+
+/* Compute the population count of THIS producing a number with
+   BITSIZE and PREC.  */
+
+wide_int
+wide_int::popcount (unsigned int bs, unsigned int prec) const
+{
+  return wide_int::from_shwi (popcount (), bs, prec);
+}
+
+/* Compute the population count of THIS.  */
+
+int
+wide_int::popcount () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = popcount_hwi (v);
+      start = len - 2;
+    }
+  else
+    {
+      if (sign_mask ())
+	count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      else
+	count = 0;
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = val[i];
+      count += popcount_hwi (v);
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = popcount (%s)\n", count, *this);
+#endif
+  return count;
+}
+
+/* Subtract of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::sub_large (const wide_int &op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the borrow in of the first element at 1.  */
+  unsigned HOST_WIDE_INT borrow = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1.len ? (unsigned HOST_WIDE_INT)op1.val[i] : mask1;
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      borrow = o0 < o1;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 - mask1 - borrow;
+      result.len++;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/* Subtract of THIS and OP1 with overflow checking.  If the result
+   overflows within the precision, set OVERFLOW.  OVERFLOW is assumed
+   to be sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::sub (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT borrow = 0;
+  unsigned HOST_WIDE_INT old_borrow = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int i, small_prec;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < len; i++)
+    {
+      o0 = val[i];
+      o1 = op1.val[i];
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  /* Uncompress the rest.  */
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = val[i];
+      o1 = mask1;
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  for (i = op1.len; i < len; i++)
+    {
+      o0 = mask0;
+      o1 = op1.val[i];
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 - mask1 - borrow;
+      result.len++;
+      /* If we were short, we could not have overflowed.  */
+      goto ex;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (sgn == wide_int::SIGNED)
+	{
+	  if (((x ^ o0) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
+	    *overflow = true;
+	}
+      else if (old_borrow)
+	{
+	  if ((~o0) <= o1)
+	    *overflow = true;
+	}
+      else
+	{
+	  if ((~o0) < o1)
+	    *overflow = true;
+	}
+    }
+  else
+    {
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  If there are any non zero bits above the prec,
+	     we overflowed. */
+	  o0 = zext_hwi (o0, small_prec);
+	  o1 = zext_hwi (o1, small_prec);
+	  x = o0 - o1 - old_borrow;
+	  if (x >> small_prec)
+	    *overflow = true;
+	}
+      else 
+	{
+	  /* Overflow in this case is easy since we can see bits beyond
+	     the precision.  If the value computed is not the sign
+	     extended value, then we have overflow.  */
+	  unsigned HOST_WIDE_INT y = sext_hwi (x, small_prec);
+	  if (x != y)
+	    *overflow = true;
+	}
+    }
+
+ ex:
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvww ("wide_int:: %s %d = (%s -O %s)\n", 
+		result, *overflow, *this, op1);
+#endif
+  return result;
+}
+
+/*
+ * Division and Mod
+ */
+
+/* Compute B_QUOTIENT and B_REMAINDER from B_DIVIDEND/B_DIVISOR.  The
+   algorithm is a small modification of the algorithm in Hacker's
+   Delight by Warren, which itself is a small modification of Knuth's
+   algorithm.  M is the number of significant elements of U however
+   there needs to be at least one extra element of B_DIVIDEND
+   allocated, N is the number of elements of B_DIVISOR.  */
+
+void
+wide_int::divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+			     unsigned HOST_HALF_WIDE_INT *b_remainder,
+			     unsigned HOST_HALF_WIDE_INT *b_dividend, 
+			     unsigned HOST_HALF_WIDE_INT *b_divisor, 
+			     int m, int n)
+{
+  /* The "digits" are a HOST_HALF_WIDE_INT which the size of half of a
+     HOST_WIDE_INT and stored in the lower bits of each word.  This
+     algorithm should work properly on both 32 and 64 bit
+     machines.  */
+  unsigned HOST_WIDE_INT b
+    = (unsigned HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT;
+  unsigned HOST_WIDE_INT qhat;   /* Estimate of quotient digit.  */
+  unsigned HOST_WIDE_INT rhat;   /* A remainder.  */
+  unsigned HOST_WIDE_INT p;      /* Product of two digits.  */
+  HOST_WIDE_INT s, i, j, t, k;
+
+  /* Single digit divisor.  */
+  if (n == 1)
+    {
+      k = 0;
+      for (j = m - 1; j >= 0; j--)
+	{
+	  b_quotient[j] = (k * b + b_dividend[j])/b_divisor[0];
+	  k = ((k * b + b_dividend[j])
+	       - ((unsigned HOST_WIDE_INT)b_quotient[j]
+		  * (unsigned HOST_WIDE_INT)b_divisor[0]));
+	}
+      b_remainder[0] = k;
+      return;
+    }
+
+  s = clz_hwi (b_divisor[n-1]) - HOST_BITS_PER_HALF_WIDE_INT; /* CHECK clz */
+
+  /* Normalize B_DIVIDEND and B_DIVISOR.  Unlike the published
+     algorithm, we can overwrite b_dividend and b_divisor, so we do
+     that.  */
+  for (i = n - 1; i > 0; i--)
+    b_divisor[i] = (b_divisor[i] << s)
+      | (b_divisor[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_divisor[0] = b_divisor[0] << s;
+
+  b_dividend[m] = b_dividend[m-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s);
+  for (i = m - 1; i > 0; i--)
+    b_dividend[i] = (b_dividend[i] << s)
+      | (b_dividend[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_dividend[0] = b_dividend[0] << s;
+
+  /* Main loop.  */
+  for (j = m - n; j >= 0; j--)
+    {
+      qhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) / b_divisor[n-1];
+      rhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) - qhat * b_divisor[n-1];
+    again:
+      if (qhat >= b || qhat * b_divisor[n-2] > b * rhat + b_dividend[j+n-2])
+	{
+	  qhat -= 1;
+	  rhat += b_divisor[n-1];
+	  if (rhat < b)
+	    goto again;
+	}
+
+      /* Multiply and subtract.  */
+      k = 0;
+      for (i = 0; i < n; i++)
+	{
+	  p = qhat * b_divisor[i];
+	  t = b_dividend[i+j] - k - (p & HALF_INT_MASK);
+	  b_dividend[i + j] = t;
+	  k = ((p >> HOST_BITS_PER_HALF_WIDE_INT)
+	       - (t >> HOST_BITS_PER_HALF_WIDE_INT));
+	}
+      t = b_dividend[j+n] - k;
+      b_dividend[j+n] = t;
+
+      b_quotient[j] = qhat;
+      if (t < 0)
+	{
+	  b_quotient[j] -= 1;
+	  k = 0;
+	  for (i = 0; i < n; i++)
+	    {
+	      t = (HOST_WIDE_INT)b_dividend[i+j] + b_divisor[i] + k;
+	      b_dividend[i+j] = t;
+	      k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	    }
+	  b_dividend[j+n] += k;
+	}
+    }
+  for (i = 0; i < n; i++)
+    b_remainder[i] = (b_dividend[i] >> s) 
+      | (b_dividend[i+1] << (HOST_BITS_PER_HALF_WIDE_INT - s));
+}
+
+
+/* Do a truncating divide DIVISOR into DIVIDEND.  The result is the
+   same size as the operands.  SIGN is either wide_int::SIGNED or
+   wide_int::UNSIGNED.  */
+
+wide_int
+wide_int::divmod_internal (bool compute_quotient, 
+			   const wide_int *dividend, const wide_int *divisor,
+			   wide_int::SignOp sgn, wide_int *remainder,
+			   bool compute_remainder, 
+			   bool *overflow)
+{
+  wide_int quotient, u0, u1;
+  unsigned int prec = dividend->get_precision();
+  unsigned int bs = dividend->get_bitsize ();
+  int blocks_needed = 2 * BLOCKS_NEEDED (prec);
+  /* The '2' in the next 4 vars are because they are built on half
+     sized wide ints.  */
+  unsigned HOST_HALF_WIDE_INT 
+    b_quotient[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_remainder[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_dividend[(MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT) + 1];
+  unsigned HOST_HALF_WIDE_INT
+    b_divisor[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  int m, n;
+  bool dividend_neg = false;
+  bool divisor_neg = false;
+
+  if ((*divisor).zero_p ())
+    *overflow = true;
+
+  /* The smallest signed number / -1 causes overflow.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      wide_int t = wide_int::set_bit_in_zero (prec - 1, 
+					      bs, 
+					      prec);
+      if (*dividend == t && (*divisor).minus_one_p ())
+	*overflow = true;
+    }
+
+  quotient.bitsize = bs;
+  remainder->bitsize = bs;
+  quotient.precision = prec;
+  remainder->precision = prec;
+
+  /* If overflow is set, just get out.  There will only be grief by
+     continuing.  */
+  if (*overflow)
+    {
+      if (compute_remainder)
+	{
+	  remainder->len = 1;
+	  remainder->val[0] = 0;
+	}
+      return wide_int::zero (bs, prec);
+    }
+
+  /* Do it on the host if you can.  */
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      quotient.len = 1;
+      remainder->len = 1;
+      if (sgn == wide_int::SIGNED)
+	{
+	  quotient.val[0] 
+	    = sext_hwi (dividend->elt (0) / divisor->val[0], prec);
+	  remainder->val[0] 
+	    = sext_hwi (dividend->elt (0) % divisor->val[0], prec);
+	}
+      else
+	{
+	  unsigned HOST_WIDE_INT o0 = dividend->elt (0);
+	  unsigned HOST_WIDE_INT o1 = divisor->elt (0);
+
+	  if (prec < HOST_BITS_PER_WIDE_INT)
+	    {
+	      o0 = zext_hwi (o0, prec);
+	      o1 = zext_hwi (o1, prec);
+	    }
+	  quotient.val[0] = sext_hwi (o0 / o1, prec);
+	  remainder->val[0] = sext_hwi (o0 % o1, prec);
+	}
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwww ("wide_int:: (q = %s) (r = %s) = (%s / %s)\n", 
+		    quotient, *remainder, *dividend, *divisor);
+#endif
+      return quotient;
+    }
+
+  /* Make the divisor and divident positive and remember what we
+     did.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      if (dividend->sign_mask ())
+	{
+	  u0 = dividend->neg ();
+	  dividend = &u0;
+	  dividend_neg = true;
+	}
+      if (divisor->sign_mask ())
+	{
+	  u1 = divisor->neg ();
+	  divisor = &u1;
+	  divisor_neg = true;
+	}
+    }
+
+  wi_unpack (b_dividend, (const unsigned HOST_WIDE_INT*)dividend->val,
+	     dividend->len, blocks_needed);
+  wi_unpack (b_divisor, (const unsigned HOST_WIDE_INT*)divisor->val, 
+	     divisor->len, blocks_needed);
+
+  if (dividend->sign_mask ())
+    m = blocks_needed;
+  else
+    m = 2 * dividend->get_len ();
+
+  if (divisor->sign_mask ())
+    n = blocks_needed;
+  else
+    n = 2 * divisor->get_len ();
+
+  /* It is known that the top input block to the divisor is non zero,
+     but when this block is split into two half blocks, it may be that
+     the top half block is zero.  Skip over this half block.  */
+  if (b_divisor[n - 1] == 0)
+    n--;
+
+  divmod_internal_2 (b_quotient, b_remainder, b_dividend, b_divisor, m, n);
+
+  if (compute_quotient)
+    {
+      wi_pack ((unsigned HOST_WIDE_INT*)quotient.val, b_quotient, m);
+      quotient.len = m / 2;
+      quotient.canonize ();
+      /* The quotient is neg if exactly one of the divisor or dividend is
+	 neg.  */
+      if (dividend_neg != divisor_neg)
+	quotient = quotient.neg ();
+    }
+  else
+    quotient = wide_int::zero (word_mode);
+
+  if (compute_remainder)
+    {
+      wi_pack ((unsigned HOST_WIDE_INT*)remainder->val, b_remainder, n);
+      if (n & 1)
+	n++;
+      remainder->len = n / 2;
+      (*remainder).canonize ();
+      /* The remainder is always the same sign as the dividend.  */
+      if (dividend_neg)
+	*remainder = (*remainder).neg ();
+    }
+  else
+    *remainder = wide_int::zero (word_mode);
+
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwww ("wide_int:: (q = %s) (r = %s) = (%s / %s)\n", 
+		quotient, *remainder, *dividend, *divisor);
+#endif
+  return quotient;
+}
+
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is
+   truncated.  */
+
+wide_int
+wide_int::div_trunc (const wide_int &divisor, SignOp sgn) const
+{
+  wide_int remainder;
+  bool overflow = false;
+
+  return divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, false, &overflow);
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is truncated.
+   Overflow is set to true if the result overflows, otherwise it is
+   not set.  */
+wide_int
+wide_int::div_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  
+  return divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, false, overflow);
+}
+
+/* Divide DIVISOR into THIS producing both the quotient and remainder.
+   The result is the same size as the operands.  The sign is specified
+   in SGN.  The output is truncated.  */
+
+wide_int
+wide_int::divmod_trunc (const wide_int &divisor, wide_int *remainder, SignOp sgn) const
+{
+  bool overflow = false;
+
+  return divmod_internal (true, this, &divisor, sgn, 
+			  remainder, true, &overflow);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  */
+
+wide_int
+wide_int::mod_trunc (const wide_int &divisor, SignOp sgn) const
+{
+  bool overflow = false;
+  wide_int remainder;
+
+  divmod_internal (false, this, &divisor, sgn, 
+		   &remainder, true, &overflow);
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+
+  divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, true, overflow);
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is floor
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return quotient - wide_int::one (bitsize, precision);
+  return quotient;
+}
+
+
+/* Divide DIVISOR into THIS.  The remainder is also produced in
+   REMAINDER.  The result is the same size as the operands.  The sign
+   is specified in SGN.  The output is floor truncated.  Overflow is
+   set to true if the result overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::divmod_floor (const wide_int &divisor, wide_int *remainder, SignOp sgn) const
+{
+  wide_int quotient;
+  bool overflow = false;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      remainder, true, &overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !(*remainder).zero_p ())
+    {
+      *remainder = *remainder - divisor;
+      return quotient - wide_int::one (bitsize, precision);
+    }
+  return quotient;
+}
+
+
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is floor truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return remainder - divisor;
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is ceil
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return quotient;
+      else
+	return quotient + wide_int::one (bitsize, precision);
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is the
+   same size as the operands.  The sign is specified in SGN.  The
+   output is ceil truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return remainder;
+      else
+	return remainder - divisor;
+    }
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is round
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_round (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+  if (!remainder.zero_p ())
+    {
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return quotient - wide_int::one (bitsize, precision);
+	      else 
+		return quotient + wide_int::one (bitsize, precision);
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return quotient + wide_int::one (bitsize, precision);
+	}
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is round truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_round (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return remainder + divisor;
+	      else 
+		return remainder - divisor;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return remainder - divisor;
+	}
+    }
+  return remainder;
+}
+
+/*
+ * Shifting, rotating and extraction.
+ */
+
+/* Extract WIDTH bits from THIS starting at OFFSET.  The result is
+   assumed to fit in a HOST_WIDE_INT.  This function is safe in that
+   it can properly access elements that may not be explicitly
+   represented.  */
+
+HOST_WIDE_INT
+wide_int::extract_to_hwi (int offset, int width) const
+{
+  int start_elt, end_elt, shift;
+  HOST_WIDE_INT x;
+
+  /* Get rid of the easy cases first.   */
+  if (offset >= len * HOST_BITS_PER_WIDE_INT)
+    return sign_mask ();
+  if (offset + width <= 0)
+    return 0;
+
+  shift = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset < 0)
+    {
+      start_elt = -1;
+      end_elt = 0;
+      x = 0;
+    }
+  else
+    {
+      start_elt = offset / HOST_BITS_PER_WIDE_INT;
+      end_elt = (offset + width - 1) / HOST_BITS_PER_WIDE_INT;
+      x = start_elt >= len ? sign_mask () : val[start_elt] >> shift;
+    }
+
+  if (start_elt != end_elt)
+    {
+      HOST_WIDE_INT y = end_elt == len
+	? sign_mask () : val[end_elt];
+
+      x = (unsigned HOST_WIDE_INT)x >> shift;
+      x |= y << (HOST_BITS_PER_WIDE_INT - shift);
+    }
+
+  if (width != HOST_BITS_PER_WIDE_INT)
+    x &= ((HOST_WIDE_INT)1 << width) - 1;
+
+  return x;
+}
+
+
+/* Left shift THIS by CNT.  See the definition of Op.TRUNC for how to
+   set Z.  Since this is used internally, it has the ability to
+   specify the BISIZE and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+wide_int
+wide_int::lshift_large (unsigned int cnt, 
+			unsigned int bs, unsigned int res_prec) const
+{
+  wide_int result;
+  unsigned int i;
+
+  result.bitsize = bs;
+  result.precision = res_prec;
+
+  if (cnt >= res_prec)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+      return result;
+    }
+
+  for (i = 0; i < res_prec; i += HOST_BITS_PER_WIDE_INT)
+    result.val[i / HOST_BITS_PER_WIDE_INT]
+      = extract_to_hwi (i - cnt, HOST_BITS_PER_WIDE_INT);
+
+  result.len = BLOCKS_NEEDED (res_prec);
+  result.canonize ();
+
+  return result;
+}
+
+/* Rotate THIS left by CNT within its precision.  */
+
+wide_int
+wide_int::lrotate (unsigned int cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (cnt, NONE);
+  right = rshiftu (precision - cnt, NONE);
+  result = left | right;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s lrotate %d)\n", result, *this, cnt);
+#endif
+  return result;
+}
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set Z.  */
+
+wide_int
+wide_int::rshiftu_large (unsigned int cnt) const
+{
+  wide_int result;
+  int stop_block, offset, i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (cnt >= precision)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  offset = (precision - cnt) & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset)
+    result.val[stop_block - 1] = zext_hwi (result.val[stop_block - 1], offset);
+  else
+    /* The top block had a 1 at the top position so it will decompress
+       wrong unless a zero block is added.  This only works because we
+       know the shift was greater than 0.  */
+    if (result.val[stop_block - 1] < 0)
+      result.val[result.len++] = 0;
+  return result;
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set Z.  */
+
+wide_int
+wide_int::rshifts_large (unsigned int cnt) const
+{
+  wide_int result;
+  int stop_block, i;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (cnt >= precision)
+    {
+      HOST_WIDE_INT m = sign_mask ();
+      result.val[0] = m;
+      result.len = 1;
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  /* No need to sign extend the last block, since it extract_to_hwi
+     already did that.  */
+  return result;
+}
+
+/* Rotate THIS right by CNT within its precision.  */
+
+wide_int
+wide_int::rrotate (unsigned int cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (precision - cnt, NONE);
+  right = rshiftu (cnt, NONE);
+  result = left | right;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s rrotate %d)\n", result, *this, cnt);
+#endif
+  return result;
+}
+
+/*
+ * Private utilities.
+ */
+/* Decompress THIS for at least TARGET bits into a result with bitsize
+   BS and precision PREC.  */
+
+wide_int
+wide_int::decompress (unsigned int target, 
+		      unsigned int bs, unsigned int prec) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (target);
+  HOST_WIDE_INT mask;
+  int len, i;
+
+  result.bitsize = bs;
+  result.precision = prec;
+  result.len = blocks_needed;
+
+  for (i = 0; i < this->len; i++)
+    result.val[i] = val[i];
+
+  len = this->len;
+
+  if (target > result.precision)
+    return result;
+
+  /* The extension that we are doing here is not sign extension, it is
+     decompression.  */
+  mask = sign_mask ();
+  while (len < blocks_needed)
+    result.val[len++] = mask;
+
+  return result;
+}
+
+
+/*
+ * Private debug printing routines.
+ */
+
+/* The debugging routines print results of wide operations into the
+   dump files of the respective passes in which they were called.  */
+char *
+wide_int::dump (char* buf) const
+{
+  int i;
+  int l;
+  const char * sep = "";
+
+  l = sprintf (buf, "[%d,%d (", bitsize, precision);
+  for (i = len - 1; i >= 0; i--)
+    {
+      l += sprintf (&buf[l], "%s" HOST_WIDE_INT_PRINT_HEX, sep, val[i]);
+      sep = " ";
+    }
+
+  gcc_assert (len != 0);
+
+  l += sprintf (&buf[l], ")]");
+
+  gcc_assert (l < MAX_SIZE);
+  return buf;
+}
+
+#ifdef DEBUG_WIDE_INT
+void
+wide_int::debug_vw (const char* fmt, int r, const wide_int& o0)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r, o0.dump (buf0));
+}
+
+void
+wide_int::debug_vwh (const char* fmt, int r, const wide_int &o0,
+		     HOST_WIDE_INT o1)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r, o0.dump (buf0), o1);
+}
+
+void
+wide_int::debug_vww (const char* fmt, int r, const wide_int &o0,
+		     const wide_int &o1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r, o0.dump (buf0), o1.dump (buf1));
+}
+
+void
+wide_int::debug_wh (const char* fmt, const wide_int &r,
+		    HOST_WIDE_INT o1)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o1);
+}
+
+void
+wide_int::debug_whh (const char* fmt, const wide_int &r,
+		     HOST_WIDE_INT o1, HOST_WIDE_INT o2)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o1, o2);
+}
+
+void
+wide_int::debug_wv (const char* fmt, const wide_int &r, int v0)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0);
+}
+
+void
+wide_int::debug_wvv (const char* fmt, const wide_int &r,
+		     int v0, int v1)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0, v1);
+}
+
+void
+wide_int::debug_wvvv (const char* fmt, const wide_int &r,
+		      int v0, int v1, int v2)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0, v1, v2);
+}
+
+void
+wide_int::debug_wvww (const char* fmt, const wide_int &r, int v0,
+		      const wide_int &o0, const wide_int &o1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0,
+	   o0.dump (buf1), o1.dump (buf2));
+}
+
+void
+wide_int::debug_ww (const char* fmt, const wide_int &r,
+		    const wide_int &o0)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1));
+}
+
+void
+wide_int::debug_wwv (const char* fmt, const wide_int &r,
+		     const wide_int &o0, int v0)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1), v0);
+}
+
+void
+wide_int::debug_wwvvs (const char* fmt, const wide_int &r, 
+		       const wide_int &o0, int v0, int v1,
+		       const char *s)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1), v0, v1, s);
+}
+
+void
+wide_int::debug_wwwvv (const char* fmt, const wide_int &r,
+		       const wide_int &o0, const wide_int &o1,
+		       int v0, int v1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), v0, v1);
+}
+
+void
+wide_int::debug_www (const char* fmt, const wide_int &r,
+		     const wide_int &o0, const wide_int &o1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2));
+}
+
+void
+wide_int::debug_wwww (const char* fmt, const wide_int &r,
+		      const wide_int &o0, const wide_int &o1,
+		      const wide_int &o2)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  char buf3[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), o2.dump (buf3));
+}
+#endif
+
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
new file mode 100644
index 0000000..fdd1ddb
--- /dev/null
+++ b/gcc/wide-int.h
@@ -0,0 +1,2340 @@
+/* Operations with very long integers.
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef WIDE_INT_H
+#define WIDE_INT_H
+
+/* A wide integer is currently represented as a vector of
+   HOST_WIDE_INTs.  The vector contains enough elements to hold a
+   value of MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT which is
+   a derived for each host target combination.  The values are stored
+   in the vector with the least signicant HOST_BITS_PER_WIDE_INT bits
+   of the value stored in element 0.
+
+   A wide_int contains four fields: the vector (VAL), the bitsize,
+   precision and a length, (LEN).  The length is the number of HWIs
+   needed to represent the value.
+
+   Since most integers used in a compiler are small values, it is
+   generally profitable to use a representation of the value that is
+   shorter than the modes precision.  LEN is used to indicate the
+   number of elements of the vector that are in use.  When LEN *
+   HOST_BITS_PER_WIDE_INT < the precision, the value has been
+   compressed.  The values of the elements of the vector greater than
+   LEN - 1. are all equal to the highest order bit of LEN.
+
+   The representation does not contain any information about
+   signedness of the represented value, so it can be used to represent
+   both signed and unsigned numbers.  For operations where the results
+   depend on signedness (division, comparisons), the signedness must
+   be specified separately.  For operations where the signness
+   matters, one of the operands to the operation specifies either
+   wide_int::SIGNED or wide_int::UNSIGNED.
+
+   All constructors for wide_int take either a bitsize and precision,
+   an enum machine_mode or tree_type.  */
+
+
+#ifndef GENERATOR_FILE
+#include "tree.h"
+#include "hwint.h"
+#include "options.h"
+#include "tm.h"
+#include "insn-modes.h"
+#include "machmode.h"
+#include "double-int.h"
+#include <gmp.h>
+#include "insn-modes.h"
+#include "dumpfile.h"
+
+#define DEBUG_WIDE_INT
+
+class wide_int {
+  /* Internal representation.  */
+  
+  /* VAL is set to a size that is capable of computing a full
+     multiplication on the largest mode that is represented on the
+     target.  The full multiplication is use by tree-vrp.  tree-vpn
+     currently does a 2x largest mode by 2x largest mode yielding a 4x
+     largest mode result.  If operations are added that require larger
+     buffers, then VAL needs to be changed.  */
+  HOST_WIDE_INT val[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  unsigned short len;
+  unsigned int bitsize;
+  unsigned int precision;
+
+ public:
+  enum ShiftOp {
+    NONE,
+    /* There are two uses for the wide-int shifting functions.  The
+       first use is as an emulation of the target hardware.  The
+       second use is as service routines for other optimizations.  The
+       first case needs to be identified by passing TRUNC as the value
+       of ShiftOp so that shift amount is properly handled according to the
+       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
+       amount is always truncated by the bytesize of the mode of
+       THIS.  */
+    TRUNC
+  };
+
+  enum SignOp {
+    /* Many of the math functions produce different results depending
+       on if they are SIGNED or UNSIGNED.  In general, there are two
+       different functions, whose names are prefixed with an 'S" and
+       or an 'U'.  However, for some math functions there is also a
+       routine that does not have the prefix and takes an SignOp
+       parameter of SIGNED or UNSIGNED.  */
+    SIGNED,
+    UNSIGNED
+  };
+
+  /* Conversions.  */
+
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize, 
+				    unsigned int precision);
+  static wide_int from_shwi (HOST_WIDE_INT op0, unsigned int bitsize, 
+			     unsigned int precision, bool *overflow);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, unsigned int bitsize, 
+				    unsigned int precision);
+  static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, unsigned int bitsize, 
+			     unsigned int precision, bool *overflow);
+
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type);
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type, 
+				   bool *overflow);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+				    bool *overflow);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+				    enum machine_mode mode);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+				    enum machine_mode mode, 
+				    bool *overflow);
+  static wide_int from_array (const HOST_WIDE_INT* op0,
+			      unsigned int len,
+			      unsigned int bitsize, 
+			      unsigned int precision); 
+  inline static wide_int from_array (const HOST_WIDE_INT* op0,
+				     unsigned int len,
+				     enum machine_mode mode);
+  inline static wide_int from_array (const HOST_WIDE_INT* op0,
+				     unsigned int len,
+				     const_tree type);
+
+  static wide_int from_double_int (double_int, 
+				   unsigned int bitsize, 
+				   unsigned int precision);
+  inline static wide_int from_double_int (double_int, enum machine_mode);
+  static wide_int from_tree (const_tree);
+  static wide_int from_tree_as_infinite_precision (const_tree tcst, 
+						   unsigned int bitsize, 
+						   unsigned int precision);
+  static wide_int from_rtx (const_rtx, enum machine_mode);
+
+  inline HOST_WIDE_INT to_shwi () const;
+  inline HOST_WIDE_INT to_shwi (unsigned int prec) const;
+  inline unsigned HOST_WIDE_INT to_uhwi () const;
+  inline unsigned HOST_WIDE_INT to_uhwi (unsigned int prec) const;
+
+  /* Largest and smallest values that are represented in modes or precisions.  */
+
+  static wide_int max_value (unsigned int prec, unsigned int bitsize, 
+			     unsigned int precision, SignOp sgn);
+  inline static wide_int max_value (unsigned int bitsize, 
+				    unsigned int precision, SignOp sgn);
+  inline static wide_int max_value (const_tree type);
+  inline static wide_int max_value (enum machine_mode mode, SignOp sgn);
+  
+  static wide_int min_value (unsigned int prec, unsigned int bitsize, 
+			     unsigned int precision, SignOp sgn);
+  inline static wide_int min_value (unsigned int bitsize, 
+				    unsigned int precision, SignOp sgn);
+  inline static wide_int min_value (const_tree type);
+  inline static wide_int min_value (enum machine_mode mode, SignOp sgn);
+  
+  /* Small constants */
+
+  inline static wide_int minus_one (unsigned int bitsize, unsigned int prec);
+  inline static wide_int minus_one (const_tree type);
+  inline static wide_int minus_one (enum machine_mode mode);
+  inline static wide_int minus_one (const wide_int &op1);
+  inline static wide_int zero (unsigned int bitsize, unsigned int prec);
+  inline static wide_int zero (const_tree type);
+  inline static wide_int zero (enum machine_mode mode);
+  inline static wide_int zero (const wide_int &op1);
+  inline static wide_int one (unsigned int bitsize, unsigned int prec);
+  inline static wide_int one (const_tree type);
+  inline static wide_int one (enum machine_mode mode);
+  inline static wide_int one (const wide_int &op1);
+  inline static wide_int two (unsigned int bitsize, unsigned int prec);
+  inline static wide_int two (const_tree type);
+  inline static wide_int two (enum machine_mode mode);
+  inline static wide_int two (const wide_int &op1);
+
+  /* Accessors.  */
+
+  inline unsigned short get_len () const;
+  inline unsigned int get_bitsize () const;
+  inline unsigned int get_precision () const;
+  inline HOST_WIDE_INT elt (unsigned int i) const;
+
+  /* Printing functions.  */
+
+  void print_dec (char *buf, SignOp sgn) const;
+  void print_dec (FILE *file, SignOp sgn) const;
+  void print_decs (char *buf) const;
+  void print_decs (FILE *file) const;
+  void print_decu (char *buf) const;
+  void print_decu (FILE *file) const;
+  void print_hex (char *buf) const;
+  void print_hex (FILE *file) const;
+
+  /* Comparative functions.  */
+
+  inline bool minus_one_p () const;
+  inline bool zero_p () const;
+  inline bool one_p () const;
+  inline bool neg_p () const;
+
+  inline bool operator == (const wide_int &y) const;
+  inline bool operator != (const wide_int &y) const;
+  inline bool gt_p (HOST_WIDE_INT x, SignOp sgn) const;
+  inline bool gt_p (const wide_int &x, SignOp sgn) const;
+  inline bool gts_p (HOST_WIDE_INT y) const;
+  inline bool gts_p (const wide_int &y) const;
+  inline bool gtu_p (unsigned HOST_WIDE_INT y) const;
+  inline bool gtu_p (const wide_int &y) const;
+
+  inline bool lt_p (const HOST_WIDE_INT x, SignOp sgn) const;
+  inline bool lt_p (const wide_int &x, SignOp sgn) const;
+  inline bool lts_p (HOST_WIDE_INT y) const;
+  inline bool lts_p (const wide_int &y) const;
+  inline bool ltu_p (unsigned HOST_WIDE_INT y) const;
+  inline bool ltu_p (const wide_int &y) const;
+  inline int cmp (const wide_int &y, SignOp sgn) const;
+  inline int cmps (const wide_int &y) const;
+  inline int cmpu (const wide_int &y) const;
+
+  bool only_sign_bit_p (unsigned int prec) const;
+  inline bool only_sign_bit_p () const;
+  inline bool fits_uhwi_p () const;
+  inline bool fits_shwi_p () const;
+  bool fits_to_tree_p (const_tree type) const;
+  bool fits_u_p (unsigned int prec) const;
+  bool fits_s_p (unsigned int prec) const;
+
+  /* Min and max */
+
+  inline wide_int min (const wide_int &op1, SignOp sgn) const;
+  inline wide_int max (const wide_int &op1, SignOp sgn) const;
+  inline wide_int smin (const wide_int &op1) const;
+  inline wide_int smax (const wide_int &op1) const;
+  inline wide_int umin (const wide_int &op1) const;
+  inline wide_int umax (const wide_int &op1) const;
+
+  /* Extension, these do not change the precision or bitsize.  */
+
+  inline wide_int ext (unsigned int offset, SignOp sgn) const;
+  wide_int sext (unsigned int offset) const;
+  wide_int zext (unsigned int offset) const;
+
+  /* Make a fast copy.  */
+
+  wide_int copy () const;
+
+  /* These change the underlying bitsize and precision.  */
+  
+  wide_int force_to_size (unsigned int bitsize, unsigned int precision, 
+			  SignOp sgn) const;
+  inline wide_int force_to_size (enum machine_mode mode, SignOp sgn) const;
+  inline wide_int force_to_size (const_tree type) const;
+  inline wide_int force_to_size (const_tree type, SignOp sgn) const;
+
+  inline wide_int sforce_to_size (enum machine_mode mode) const;
+  inline wide_int sforce_to_size (const_tree type) const;
+  inline wide_int zforce_to_size (enum machine_mode mode) const;
+  inline wide_int zforce_to_size (const_tree type) const;
+
+  /* Masking, and Insertion  */
+
+  wide_int set_bit (unsigned int bitpos) const;
+  static wide_int set_bit_in_zero (unsigned int, 
+				   unsigned int bitsize, 
+				   unsigned int prec);
+  inline static wide_int set_bit_in_zero (unsigned int, 
+					  enum machine_mode mode);
+  inline static wide_int set_bit_in_zero (unsigned int, const_tree type);
+  wide_int insert (const wide_int &op0, unsigned int offset,
+		   unsigned int width) const;
+  static wide_int mask (unsigned int start, bool negate, 
+			unsigned int bitsize, unsigned int prec);
+  inline static wide_int mask (unsigned int start, bool negate, 
+			       enum machine_mode mode);
+  inline static wide_int mask (unsigned int start, bool negate,
+			       const_tree type);
+  wide_int bswap () const;
+  static wide_int shifted_mask (unsigned int start, unsigned int width,
+				bool negate,
+				unsigned int bitsize, unsigned int prec);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, enum machine_mode mode);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, const_tree type);
+  inline HOST_WIDE_INT sign_mask () const;
+
+  /* Logicals */
+
+  inline wide_int operator & (const wide_int &y) const;
+  inline wide_int and_not (const wide_int &y) const;
+  inline wide_int operator ~ () const;
+  inline wide_int operator | (const wide_int &y) const;
+  inline wide_int or_not (const wide_int &y) const;
+  inline wide_int operator ^ (const wide_int &y) const;
+
+  /* Arithmetic operation functions, alpha sorted.  */
+
+  wide_int abs () const;
+  inline wide_int operator + (const wide_int &y) const;
+  wide_int add (const wide_int &x, SignOp sgn, bool *overflow) const;
+  wide_int clz (unsigned int bitsize, unsigned int prec) const;
+  int clz () const;
+  wide_int clrsb (unsigned int bitsize, unsigned int prec) const;
+  int clrsb () const;
+  wide_int ctz (unsigned int bitsize, unsigned int prec) const;
+  int ctz () const;
+  int exact_log2 () const;
+  int floor_log2 () const;
+  wide_int ffs () const;
+  inline wide_int operator * (const wide_int &y) const;
+  wide_int mul (const wide_int &x, SignOp sgn, bool *overflow) const;
+  inline wide_int smul (const wide_int &x, bool *overflow) const;
+  inline wide_int umul (const wide_int &x, bool *overflow) const;
+  wide_int mul_full (const wide_int &x, SignOp sgn) const;
+  inline wide_int umul_full (const wide_int &x) const;
+  inline wide_int smul_full (const wide_int &x) const;
+  wide_int mul_high (const wide_int &x, SignOp sgn) const;
+  inline wide_int neg () const;
+  inline wide_int neg (bool *overflow) const;
+  wide_int parity (unsigned int bitsize, unsigned int prec) const;
+  int popcount () const;
+  wide_int popcount (unsigned int bitsize, unsigned int prec) const;
+  inline wide_int operator - (const wide_int &y) const;
+  wide_int sub (const wide_int &x, SignOp sgn, bool *overflow) const;
+
+  /* Divison and mod.  These are the ones that are actually used, but
+     there are a lot of them.  */
+
+  wide_int div_trunc (const wide_int &divisor, SignOp sgn) const;
+  wide_int div_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int sdiv_trunc (const wide_int &divisor) const;
+  inline wide_int udiv_trunc (const wide_int &divisor) const;
+
+  wide_int div_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int udiv_floor (const wide_int &divisor) const;
+  inline wide_int sdiv_floor (const wide_int &divisor) const;
+  wide_int div_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  wide_int div_round (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+
+  wide_int divmod_trunc (const wide_int &divisor, wide_int *mod, SignOp sgn) const;
+  inline wide_int sdivmod_trunc (const wide_int &divisor, wide_int *mod) const;
+  inline wide_int udivmod_trunc (const wide_int &divisor, wide_int *mod) const;
+
+  wide_int divmod_floor (const wide_int &divisor, wide_int *mod, SignOp sgn) const;
+  inline wide_int sdivmod_floor (const wide_int &divisor, wide_int *mod) const;
+
+  wide_int mod_trunc (const wide_int &divisor, SignOp sgn) const;
+  wide_int mod_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int smod_trunc (const wide_int &divisor) const;
+  inline wide_int umod_trunc (const wide_int &divisor) const;
+
+  wide_int mod_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  inline wide_int umod_floor (const wide_int &divisor) const;
+  wide_int mod_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+  wide_int mod_round (const wide_int &divisor, SignOp sgn, bool *overflow) const;
+
+  /* Shifting rotating and extracting.  */
+  HOST_WIDE_INT extract_to_hwi (int offset, int width) const;
+
+  inline wide_int lshift (const wide_int &y, ShiftOp z = NONE) const;
+  inline wide_int lshift (unsigned int y, ShiftOp z, unsigned int bitsize, 
+			  unsigned int precision) const;
+  inline wide_int lshift (unsigned int y, ShiftOp z = NONE) const;
+
+  inline wide_int lrotate (const wide_int &y) const;
+  wide_int lrotate (unsigned int y) const;
+
+  inline wide_int rshift (const wide_int &y, SignOp sgn, ShiftOp z = NONE) const;
+  inline wide_int rshiftu (const wide_int &y, ShiftOp z = NONE) const;
+  inline wide_int rshiftu (unsigned int y, ShiftOp z = NONE) const;
+  inline wide_int rshifts (const wide_int &y, ShiftOp z = NONE) const;
+  inline wide_int rshifts (unsigned int y, ShiftOp z = NONE) const;
+
+  inline wide_int rrotate (const wide_int &y) const;
+  wide_int rrotate (unsigned int y) const;
+
+  static const int DUMP_MAX = (2 * (MAX_BITSIZE_MODE_ANY_INT / 4
+			       + MAX_BITSIZE_MODE_ANY_INT 
+				    / HOST_BITS_PER_WIDE_INT + 32));
+  char *dump (char* buf) const;
+ private:
+
+  /* 
+   * Internal versions that do the work if the values do not fit in a
+   * HWI.
+   */ 
+
+  /* Comparisons */
+  bool eq_p_large (const wide_int &op1) const;
+  bool lts_p_large (const wide_int &op1) const;
+  int cmps_large (const wide_int &op1) const;
+  bool ltu_p_large (const wide_int &op1) const;
+  int cmpu_large (const wide_int &op1) const;
+
+  /* Logicals.  */
+  wide_int and_large (const wide_int &op1) const;
+  wide_int and_not_large (const wide_int &y) const;
+  wide_int or_large (const wide_int &y) const;
+  wide_int or_not_large (const wide_int &y) const;
+  wide_int xor_large (const wide_int &y) const;
+
+  /* Arithmetic */
+  wide_int add_large (const wide_int &op1) const;
+  wide_int sub_large (const wide_int &op1) const;
+
+  wide_int lshift_large (unsigned int cnt, 
+			 unsigned int bs, unsigned int res_prec) const;
+  wide_int rshiftu_large (unsigned int cnt) const;
+  wide_int rshifts_large (unsigned int cnt) const;
+
+  static wide_int
+    mul_internal (bool high, bool full, 
+		  const wide_int *op1, const wide_int *op2,
+		  wide_int::SignOp sgn,  bool *overflow, bool needs_overflow);
+  static void
+    divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+		       unsigned HOST_HALF_WIDE_INT *b_remainder,
+		       unsigned HOST_HALF_WIDE_INT *b_dividend, 
+		       unsigned HOST_HALF_WIDE_INT *b_divisor, 
+		       int m, int n);
+  static wide_int
+    divmod_internal (bool compute_quotient, 
+		     const wide_int *dividend, const wide_int *divisor,
+		     wide_int::SignOp sgn, wide_int *remainder,
+		     bool compute_remainder, 
+		     bool *overflow);
+
+
+  /* Private utility routines.  */
+  wide_int decompress (unsigned int target, unsigned int bitsize, 
+		       unsigned int precision) const;
+  void canonize ();
+  static inline int trunc_shift (unsigned int bitsize, int cnt);
+  static inline int trunc_shift (unsigned int bitsize, const wide_int &cnt, ShiftOp z);
+
+#ifdef DEBUG_WIDE_INT
+  /* Debugging routines.  */
+  static void debug_vw  (const char* fmt, int r, const wide_int& o0);
+  static void debug_vwh (const char* fmt, int r, const wide_int &o0,
+			 HOST_WIDE_INT o1);
+  static void debug_vww (const char* fmt, int r, const wide_int &o0,
+			 const wide_int &o1);
+  static void debug_wh (const char* fmt, const wide_int &r,
+			 HOST_WIDE_INT o1);
+  static void debug_whh (const char* fmt, const wide_int &r,
+			 HOST_WIDE_INT o1, HOST_WIDE_INT o2);
+  static void debug_wv (const char* fmt, const wide_int &r, int v0);
+  static void debug_wvv (const char* fmt, const wide_int &r, int v0,
+			 int v1);
+  static void debug_wvvv (const char* fmt, const wide_int &r, int v0,
+			  int v1, int v2);
+  static void debug_wvww (const char* fmt, const wide_int &r, int v0,
+			  const wide_int &o0, const wide_int &o1);
+  static void debug_wwv (const char* fmt, const wide_int &r,
+			 const wide_int &o0, int v0);
+  static void debug_wwvvs (const char* fmt, const wide_int &r, 
+			   const wide_int &o0, 
+			   int v0, int v1, const char *s);
+  static void debug_wwwvv (const char* fmt, const wide_int &r,
+			   const wide_int &o0, const wide_int &o1,
+			   int v0, int v1);
+  static void debug_ww (const char* fmt, const wide_int &r,
+			const wide_int &o0);
+  static void debug_www (const char* fmt, const wide_int &r,
+			 const wide_int &o0, const wide_int &o1);
+  static void debug_wwww (const char* fmt, const wide_int &r,
+			  const wide_int &o0, const wide_int &o1, 
+			  const wide_int &o2);
+#endif
+};
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with bitsize
+   and precision taken from MODE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, enum machine_mode mode)
+{
+  return wide_int::set_bit_in_zero (bitpos, GET_MODE_BITSIZE (mode),
+				    GET_MODE_PRECISION (mode));
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with bitsize
+   and precision taken from TYPE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, const_tree type)
+{
+
+  return wide_int::set_bit_in_zero (bitpos, 
+				    GET_MODE_BITSIZE (TYPE_MODE (type)),
+				    TYPE_PRECISION (type));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.   The result is made with bitsize
+   and precision taken from MODE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, enum machine_mode mode)
+{
+  return wide_int::mask (width, negate, 
+			 GET_MODE_BITSIZE (mode),
+			 GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with bitsize
+   and precision taken from TYPE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, const_tree type)
+{
+
+  return wide_int::mask (width, negate, 
+			 GET_MODE_BITSIZE (TYPE_MODE (type)),
+			 TYPE_PRECISION (type));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the bits
+   above that up to the precision are zeros.  The result is inverted
+   if NEGATE is true.  The result is made with bitsize and precision
+   taken from MODE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, enum machine_mode mode)
+{
+  return wide_int::shifted_mask (start, width, negate, 
+				 GET_MODE_BITSIZE (mode),
+				 GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with bitsize
+   and precision taken from TYPE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, const_tree type)
+{
+
+  return wide_int::shifted_mask (start, width, negate, 
+				 GET_MODE_BITSIZE (TYPE_MODE (type)),
+				 TYPE_PRECISION (type));
+}
+
+/* Produce 0 or -1 that is the smear of the sign bit.  */
+
+HOST_WIDE_INT
+wide_int::sign_mask () const
+{
+  int i = len - 1;
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
+	    >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* VRP appears to be badly broken and this is a very ugly fix.  */
+  if (i >= 0)
+    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
+
+  gcc_unreachable ();
+#if 0
+  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
+#endif
+}
+
+/* Conversions */
+
+/* Convert OP0 into a wide_int with parameters taken from TYPE.  */
+
+wide_int
+wide_int::from_hwi (HOST_WIDE_INT op0, const_tree type)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return wide_int::from_uhwi (op0, bitsize, prec);
+  else
+    return wide_int::from_shwi (op0, bitsize, prec);
+}
+
+/* Convert OP0 into a wide_int with parameters taken from TYPE.  If
+   the value does not fit, set OVERFLOW.  */
+
+wide_int
+wide_int::from_hwi (HOST_WIDE_INT op0, const_tree type, 
+		    bool *overflow)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return wide_int::from_uhwi (op0, bitsize, prec, overflow);
+  else
+    return wide_int::from_shwi (op0, bitsize, prec, overflow);
+}
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, unsigned int bitsize, unsigned int precision)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    op0 = sext_hwi (op0, precision);
+
+  result.val[0] = op0;
+  result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wh ("wide_int::from_uhwi %s = " HOST_WIDE_INT_PRINT_HEX "\n", 
+	      result, op0);
+#endif
+
+  return result;
+}
+
+/* Convert signed OP0 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_shwi (op0, bitsize, prec);
+}
+
+/* Convert signed OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+	   bool *overflow)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_shwi (op0, bitsize, prec, overflow);
+}
+
+/* Convert OP0 into a wide int of BITSIZE and PRECISION.  If the
+   precision is less than HOST_BITS_PER_WIDE_INT, zero extend the
+   value of the word.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0,
+		     unsigned int bitsize, unsigned int precision)
+{
+  wide_int result;
+
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    op0 = zext_hwi (op0, precision);
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && precision > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wh ("wide_int::from_uhwi %s = " HOST_WIDE_INT_PRINT_HEX "\n", 
+	      result, op0);
+#endif
+
+  return result;
+}
+
+/* Convert unsigned OP0 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_uhwi (op0, bitsize, prec);
+}
+
+/* Convert unsigned OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode, 
+		     bool *overflow)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_uhwi (op0, bitsize, prec, overflow);
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = sext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS is too large for
+   the mode's precision, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi () const
+{
+  return to_shwi (precision);
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = zext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS is too large for
+   the mode's precision, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi () const
+{
+  return to_uhwi (precision);
+}
+
+
+/* Convert OP0 of LEN into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT* op0, unsigned int len, 
+		      enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_array (op0, len, bitsize, prec);
+}
+
+/* Convert OP0 of LEN into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT* op0, unsigned int len, 
+		      const_tree type)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return wide_int::from_array (op0, len, bitsize, prec);
+}
+
+/* Convert double_int OP0 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_double_int (double_int op0, enum machine_mode mode)
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_double_int (op0, bitsize, prec);
+}
+
+/* Min and Max value helpers.  */
+
+/* Produce the largest SGNed number that is represented in PRECISION.
+   The result is represented in BITSIZE and PRECISION.  SGN must be
+   SIGNED or UNSIGNED.  */
+
+wide_int
+wide_int::max_value (unsigned int bitsize, unsigned int precision, 
+		     SignOp sgn)
+{
+  return max_value (precision, bitsize, precision, sgn);
+}
+  
+/* Produce the largest number that is represented in MODE. The
+   bitsize and precision are taken from mode.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (enum machine_mode mode, SignOp sgn)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+  return max_value (prec, GET_MODE_BITSIZE (mode), prec, sgn);
+}
+
+/* Produce the largest number that is represented in TYPE. The
+   bitsize and precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::max_value (const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  return max_value (prec, GET_MODE_BITSIZE (TYPE_MODE (type)), 
+		    prec, 
+		    TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+/* Produce the smallest SGNed number that is represented in PRECISION.
+   The result is represented in BITSIZE and PRECISION.  SGN must be
+   SIGNED or UNSIGNED.  */
+
+wide_int
+wide_int::min_value (unsigned int bitsize, unsigned int precision, 
+		     SignOp sgn)
+{
+  return min_value (precision, bitsize, precision, sgn);
+}
+  
+/* Produce the smallest number that is represented in MODE. The
+   bitsize and precision are taken from mode.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::min_value (enum machine_mode mode, SignOp sgn)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+  return min_value (prec, GET_MODE_BITSIZE (mode), prec, sgn);
+}
+
+/* Produce the smallest number that is represented in TYPE. The
+   bitsize and precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::min_value (const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  return min_value (prec, GET_MODE_BITSIZE (TYPE_MODE (type)), 
+		    prec, 
+		    TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+
+/* Small constants.  */
+
+/* Return a wide int of -1 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::minus_one (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (-1, bs, prec);
+}
+
+/* Return a wide int of -1 with TYPE.  */
+
+wide_int
+wide_int::minus_one (const_tree type)
+{
+  return wide_int::from_shwi (-1, TYPE_MODE (type));
+}
+
+/* Return a wide int of -1 with MODE.  */
+
+wide_int
+wide_int::minus_one (enum machine_mode mode)
+{
+  return wide_int::from_shwi (-1, mode);
+}
+
+/* Return a wide int of -1 that is the same size as op1.  */
+
+wide_int
+wide_int::minus_one (const wide_int &op1)
+{
+  return wide_int::from_shwi (-1, op1.get_bitsize (), op1.get_precision ());
+}
+
+
+/* Return a wide int of 0 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::zero (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (0, bs, prec);
+}
+
+/* Return a wide int of 0 with TYPE.  */
+
+wide_int
+wide_int::zero (const_tree type)
+{
+  return wide_int::from_shwi (0, TYPE_MODE (type));
+}
+
+/* Return a wide int of 0 with MODE.  */
+
+wide_int
+wide_int::zero (enum machine_mode mode)
+{
+  return wide_int::from_shwi (0, mode);
+}
+
+/* Return a wide int of 0 that is the same size as op1.  */
+
+wide_int
+wide_int::zero (const wide_int &op1)
+{
+  return wide_int::from_shwi (0, op1.get_bitsize (), op1.get_precision ());
+}
+
+
+/* Return a wide int of 1 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::one (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (1, bs, prec);
+}
+
+/* Return a wide int of 1 with TYPE.  */
+
+wide_int
+wide_int::one (const_tree type)
+{
+  return wide_int::from_shwi (1, TYPE_MODE (type));
+}
+
+/* Return a wide int of 1 with MODE.  */
+
+wide_int
+wide_int::one (enum machine_mode mode)
+{
+  return wide_int::from_shwi (1, mode);
+}
+
+/* Return a wide int of 1 that is the same size as op1.  */
+
+wide_int
+wide_int::one (const wide_int &op1)
+{
+  return wide_int::from_shwi (1, op1.get_bitsize (), op1.get_precision ());
+}
+
+
+/* Return a wide int of 2 with bitsize BS and precision PREC.  */
+
+wide_int
+wide_int::two (unsigned int bs, unsigned int prec)
+{
+  return wide_int::from_shwi (2, bs, prec);
+}
+
+/* Return a wide int of 2 with TYPE.  */
+
+wide_int
+wide_int::two (const_tree type)
+{
+  return wide_int::from_shwi (2, TYPE_MODE (type));
+}
+
+/* Return a wide int of 2 with MODE.  */
+
+wide_int
+wide_int::two (enum machine_mode mode)
+{
+  return wide_int::from_shwi (2, mode);
+}
+
+/* Return a wide int of 2 that is the same size as op1.  */
+
+wide_int
+wide_int::two (const wide_int &op1)
+{
+  return wide_int::from_shwi (2, op1.get_bitsize (), op1.get_precision ());
+}
+
+/* Public accessors for the interior of a wide int.  */
+
+/* Get the number of host wide ints actually represented within the
+   wide int.  */
+
+unsigned short
+wide_int::get_len () const
+{
+  return len;
+}
+
+/* Get bitsize of the value represented within the wide int.  */
+
+unsigned int
+wide_int::get_bitsize () const
+{
+  return bitsize;
+}
+
+/* Get precision of the value represented within the wide int.  */
+
+unsigned int
+wide_int::get_precision () const
+{
+  return precision;
+}
+
+/* Get a particular element of the wide int.  */
+
+HOST_WIDE_INT
+wide_int::elt (unsigned int i) const
+{
+  return i >= len ? sign_mask () : val[i];
+}
+
+/* Return true if THIS is -1.  */
+
+bool
+wide_int::minus_one_p () const
+{
+  return len == 1 && val[0] == (HOST_WIDE_INT)-1;
+}
+
+/* Return true if THIS is 0.  */
+
+bool
+wide_int::zero_p () const
+{
+  return len == 1 && val[0] == 0;
+}
+
+/* Return true if THIS is 1.  */
+
+bool
+wide_int::one_p () const
+{
+  return len == 1 && val[0] == 1;
+}
+
+/* Return true if THIS is negative.  */
+
+bool
+wide_int::neg_p () const
+{
+  return sign_mask () != 0;
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently signed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+bool
+wide_int::operator == (const wide_int &op1) const
+{
+  bool result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = true;
+      goto ex;
+    }
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << precision) - 1;
+      result = (val[0] & mask) == (op1.val[0] & mask);
+      goto ex;
+    }
+
+  if (precision == HOST_BITS_PER_WIDE_INT)
+    {
+      result = val[0] == op1.val[0];
+      goto ex;
+    }
+
+  result = eq_p_large (op1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s == %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS is not equal to OP1. */ 
+
+bool
+wide_int::operator != (const wide_int &op1) const
+{
+  return !(*this == op1);
+}  
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::lt_p (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (op1);
+  else
+    return ltu_p (op1);
+}  
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::gt_p (HOST_WIDE_INT op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return gts_p (op1);
+  else
+    return gtu_p (op1);
+}  
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::gt_p (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return op1.lts_p (*this);
+  else
+    return op1.ltu_p (*this);
+}  
+
+/* Return true if THIS is signed greater than OP1.  */
+
+bool
+wide_int::gts_p (const wide_int &op1) const
+{
+  return op1.lts_p (*this);
+}  
+
+/* Return true if THIS > OP1 using signed comparisons.  */
+
+bool
+wide_int::gts_p (const HOST_WIDE_INT op1) const
+{
+  bool result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] > sext_hwi (op1, precision);
+      goto ex;
+    }
+  
+  result = !neg_p ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int:: %d = (%s gts_p 0x"HOST_WIDE_INT_PRINT_HEX")\n", 
+	       result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS is unsigned greater than OP1.  */
+
+bool
+wide_int::gtu_p (const wide_int &op1) const
+{
+  return op1.ltu_p (*this);
+}  
+
+/* Return true if THIS > OP1 using unsigned comparisons.  */
+
+bool
+wide_int::gtu_p (const unsigned HOST_WIDE_INT op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  if (precision < HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1, precision);
+
+      result = x0 > x1;
+    }
+  else
+    result = true;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int:: %d = (%s gtu_p 0x"HOST_WIDE_INT_PRINT_HEX")\n", 
+	       result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::lt_p (HOST_WIDE_INT op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (op1);
+  else
+    return ltu_p (op1);
+}  
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p (const HOST_WIDE_INT op1) const
+{
+  bool result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] < sext_hwi (op1, precision);
+      goto ex;
+    }
+  
+  result = neg_p ();
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int:: %d = (%s lts_p 0x"HOST_WIDE_INT_PRINT_HEX")\n", 
+	       result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p (const wide_int &op1) const
+{
+  bool result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] < op1.val[0];
+      goto ex;
+    }
+
+  result = lts_p_large (op1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s lts_p %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p (const unsigned HOST_WIDE_INT op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  if (precision < HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1, precision);
+
+      result = x0 < x1;
+    }
+  else
+    result = false;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwh ("wide_int:: %d = (%s ltu_p 0x"HOST_WIDE_INT_PRINT_HEX")\n", 
+	       result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (op1.val[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = op1.val[0];
+	}
+
+      result = x0 < x1;
+      goto ex;
+    }
+
+  result = ltu_p_large (op1);
+
+ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s ltu_p %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Return -1 0 or 1 depending on how THIS compares with OP1.  Signness
+   is indicated by OP.  */
+
+int
+wide_int::cmp (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return cmps (op1);
+  else
+    return cmpu (op1);
+}  
+
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+int
+wide_int::cmps (const wide_int &op1) const
+{
+  int result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = 0;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      if (val[0] < op1.val[0])
+	{
+	  result = -1;
+	  goto ex;
+	}
+      if (val[0] > op1.val[0])
+	{
+	  result = 1;
+	  goto ex;
+	}
+    }
+
+  result = cmps_large (op1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s cmps %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+int
+wide_int::cmpu (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = 0;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (op1.val[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = op1.val[0];
+	}
+
+      if (x0 < x1)
+	result = -1;
+      else if (x0 == x1)
+	result = 0;
+      else
+	result = 1;
+      goto ex;
+    }
+
+  result = cmpu_large (op1);
+
+ ex:
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vww ("wide_int:: %d = (%s cmpu %s)\n", result, *this, op1);
+#endif
+
+  return result;
+}
+
+
+/* Return the signed or unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::min (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return lts_p (op1) ? (*this) : op1;
+  else
+    return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed or unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::max (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return gts_p (op1) ? (*this) : op1;
+  else
+    return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed min of THIS and OP1. */
+
+wide_int
+wide_int::smin (const wide_int &op1) const
+{
+  return lts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed max of THIS and OP1. */
+
+wide_int
+wide_int::smax (const wide_int &op1) const
+{
+  return gts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::umin (const wide_int &op1) const
+{
+  return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::umax (const wide_int &op1) const
+{
+  return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p () const
+{
+  return only_sign_bit_p (precision);
+}
+
+/* Return true if THIS fits in a HOST_WIDE_INT with no loss of
+   precision.  */
+
+bool
+wide_int::fits_shwi_p () const
+{
+  return len == 1;
+}
+
+/* Return true if THIS fits in an unsigned HOST_WIDE_INT with no loss
+   of precision.  */
+
+bool
+wide_int::fits_uhwi_p () const
+{
+  return len == 1 
+    || (len == 2 && val[1] == 0);
+}
+
+/* Return THIS extended to PREC.  The signness of the extension is
+   specified by OP.  */
+
+wide_int 
+wide_int::ext (unsigned int prec, SignOp z) const
+{
+  if (z == UNSIGNED)
+    return zext (prec);
+  else
+    return sext (prec);
+}
+
+/* Return THIS forced to the bitsize and precision of TYPE.  If this
+   is extension, the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (enum machine_mode mode, SignOp sgn) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (bitsize, prec, sgn);
+}
+
+/* Return THIS forced to the bitsize, precision and sign of TYPE.  If
+   this is extension, the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (const_tree type) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+  SignOp sgn = TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED;
+
+  return force_to_size (bitsize, prec, sgn);
+}
+
+/* Return THIS zero extended to the bitsize and precision of TYPE but
+   extends using SGN.  If this is extension, the sign is set by
+   SGN. */
+
+wide_int 
+wide_int::force_to_size (const_tree type, SignOp sgn) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (bitsize, prec, sgn);
+}
+
+/* Return THIS forced to the bitsize and precision of TYPE.  If this
+   is extension, it is signed. */
+
+wide_int 
+wide_int::sforce_to_size (enum machine_mode mode) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (bitsize, prec, SIGNED);
+}
+
+/* Return THIS zero extended to the bitsize and precision of TYPE but
+   extends using SGN.  If this is extension, it is signed. */
+
+wide_int 
+wide_int::sforce_to_size (const_tree type) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (bitsize, prec, SIGNED);
+}
+
+/* Return THIS forced to the bitsize and precision of TYPE.  If this
+   is extension, it is unsigned. */
+
+wide_int 
+wide_int::zforce_to_size (enum machine_mode mode) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (mode);
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (bitsize, prec, UNSIGNED);
+}
+
+/* Return THIS zero extended to the bitsize and precision of TYPE but
+   extends using SGN.  If this is extension, it is unsigned. */
+
+wide_int 
+wide_int::zforce_to_size (const_tree type) const
+{
+  unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (bitsize, prec, UNSIGNED);
+}
+
+/*
+ * Logicals.
+ */
+
+/* Return THIS & OP1.  */
+
+wide_int
+wide_int::operator & (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] & op1.val[0];
+    }
+  else
+    result = and_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s & %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+
+/* Return THIS & ~OP1.  */
+
+wide_int
+wide_int::and_not (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] & ~op1.val[0];
+    }
+  else
+    result = and_not_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s &~ %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+
+/* Return the logical negation (bitwise complement) of THIS.  */
+
+wide_int
+wide_int::operator ~ () const
+{
+  wide_int result;
+  int l0 = len - 1;
+
+  result.len = len;
+  result.bitsize = bitsize;
+  result.precision = precision;
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = ~val[l0];
+      l0--;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = (~ %s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+wide_int
+wide_int::operator | (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] | op1.val[0];
+    }
+  else
+    result = or_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s | %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+
+/* Return THIS | ~OP1.  */
+
+wide_int
+wide_int::or_not (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] | ~op1.val[0];
+    }
+  else
+    result = or_not_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s |~ %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+
+/* Return THIS ^ OP1.  */
+
+wide_int
+wide_int::operator ^ (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] ^ op1.val[0];
+    }
+  else
+    result = xor_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s ^ %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/*
+ * Integer arithmetic
+ */
+
+/* Return THIS + OP1.  */
+
+wide_int
+wide_int::operator + (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] + op1.val[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = add_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s + %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+/* Multiply THIS and OP1.  The result is the same precision as the
+   operands, so there is no reason for signed or unsigned
+   versions.  */
+
+wide_int
+wide_int::operator * (const wide_int &op1) const
+{
+  bool overflow = false;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      wide_int result;
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] * op1.val[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_www ("wide_int:: %s = (%s * %s)\n", result, *this, op1);
+#endif
+      return result;
+    }
+  else
+    return mul_internal (false, false, this, &op1, UNSIGNED, &overflow, false);
+}
+
+/* Negate THIS.  */
+
+wide_int
+wide_int::neg () const
+{
+  wide_int z = wide_int::from_shwi (0, bitsize, precision);
+  return z - *this;
+}
+
+/* Negate THIS.  Set overflow if the value cannot be negated.  */
+
+wide_int
+wide_int::neg (bool *overflow) const
+{
+  wide_int z = wide_int::from_shwi (0, bitsize, precision);
+  if (only_sign_bit_p ())
+    *overflow = true;
+
+  return z - *this;
+}
+
+/* Return THIS - OP1.  */
+
+wide_int
+wide_int::operator - (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] - op1.val[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = sub_large (op1);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_www ("wide_int:: %s = (%s - %s)\n", result, *this, op1);
+#endif
+  return result;
+}
+
+
+/* Signed multiply THIS and OP1.  The result is the same precision as
+   the operands.  OVERFLOW is set true if the result overflows.  */
+
+wide_int
+wide_int::smul (const wide_int &x, bool *overflow) const
+{
+  return mul (x, SIGNED, overflow);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is the same precision
+   as the operands.  OVERFLOW is set true if the result overflows.  */
+
+wide_int
+wide_int::umul (const wide_int &x, bool *overflow) const
+{
+  return mul (x, UNSIGNED, overflow);
+}
+
+/* Signed multiply THIS and OP1.  The result is twice the precision as
+   the operands.  */
+
+wide_int
+wide_int::smul_full (const wide_int &x) const
+{
+  return mul_full (x, SIGNED);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is twice the precision
+   as the operands.  */
+
+wide_int
+wide_int::umul_full (const wide_int &x) const
+{
+  return mul_full (x, UNSIGNED);
+}
+
+/* Signed divide with truncation of result.  */
+
+wide_int
+wide_int::sdiv_trunc (const wide_int &divisor) const
+{
+  return div_trunc (divisor, SIGNED);
+}
+
+/* Unsigned divide with truncation of result.  */
+
+wide_int
+wide_int::udiv_trunc (const wide_int &divisor) const
+{
+  return div_trunc (divisor, UNSIGNED);
+}
+
+/* Unsigned divide with floor truncation of result.  */
+
+wide_int
+wide_int::udiv_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return div_floor (divisor, UNSIGNED, &overflow);
+}
+
+/* Signed divide with floor truncation of result.  */
+
+wide_int
+wide_int::sdiv_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return div_floor (divisor, SIGNED, &overflow);
+}
+
+/* Signed divide/mod with truncation of result.  */
+
+wide_int
+wide_int::sdivmod_trunc (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_trunc (divisor, mod, SIGNED);
+}
+
+/* Unsigned divide/mod with truncation of result.  */
+
+wide_int
+wide_int::udivmod_trunc (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_trunc (divisor, mod, UNSIGNED);
+}
+
+/* Signed divide/mod with floor truncation of result.  */
+
+wide_int
+wide_int::sdivmod_floor (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_floor (divisor, mod, SIGNED);
+}
+
+/* Signed mod with truncation of result.  */
+
+wide_int
+wide_int::smod_trunc (const wide_int &divisor) const
+{
+  return mod_trunc (divisor, SIGNED);
+}
+
+/* Unsigned mod with truncation of result.  */
+
+wide_int
+wide_int::umod_trunc (const wide_int &divisor) const
+{
+  return mod_trunc (divisor, UNSIGNED);
+}
+
+/* Unsigned mod with floor truncation of result.  */
+
+wide_int
+wide_int::umod_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return mod_floor (divisor, UNSIGNED, &overflow);
+}
+
+/* If SHIFT_COUNT_TRUNCATED is defined, truncate CNT.   
+
+   At first look, the shift truncation code does not look right.
+   Shifts (and rotates) are done according to the precision of the
+   mode but the shift count is truncated according to the bitsize
+   of the mode.   This is how real hardware works.
+
+   On an ideal machine, like Knuth's mix machine, a shift count is a
+   word long and all of the bits of that word are examined to compute
+   the shift amount.  But on real hardware, especially on machines
+   with fast (single cycle shifts) that takes too long.  On these
+   machines, the amount of time to perform a shift dictates the cycle
+   time of the machine so corners are cut to keep this fast.  A
+   comparison of an entire 64 bit word would take something like 6
+   gate delays before the shifting can even start.
+
+   So real hardware only looks at a small part of the shift amount.
+   On ibm machines, this tends to be 1 more than what is necessary to
+   encode the shift amount.  The rest of the world looks at only the
+   minimum number of bits.  This means that only 3 gate delays are
+   necessary to set up the shifter.
+
+   On the other hand, right shifts and rotates must be according to
+   the precision or the operation does not make any sense.   */
+inline int
+wide_int::trunc_shift (unsigned int bitsize, int cnt)
+{
+#ifdef SHIFT_COUNT_TRUNCATED
+  cnt = cnt & (bitsize - 1);
+#endif
+  return cnt;
+}
+
+/* This function is called in two contexts.  If OP == TRUNC, this
+   function provides a count that matches the semantics of the target
+   machine depending on the value of SHIFT_COUNT_TRUNCATED.  Note that
+   if SHIFT_COUNT_TRUNCATED is not defined, this function may produce
+   -1 as a value if the shift amount is greater than the bitsize of
+   the mode.  -1 is a surrogate for a very large amount.
+
+   If OP == NONE, then this function always truncates the shift value
+   to the bitsize because this shifting operation is a function that
+   is internal to GCC.  */
+
+inline int
+wide_int::trunc_shift (unsigned int bitsize, const wide_int &cnt, ShiftOp z)
+{
+  if (z == TRUNC)
+    {
+#ifdef SHIFT_COUNT_TRUNCATED
+      return cnt.val[0] & (bitsize - 1);
+#else
+      if (cnt.ltu (bitsize))
+	return cnt.val[0] & (bitsize - 1);
+      else 
+	return -1;
+#endif
+    }
+  else
+    return cnt.val[0] & (bitsize - 1);
+}
+
+/* Left shift by an integer Y.  See the definition of Op.TRUNC for how
+   to set Z.  */
+
+wide_int
+wide_int::lshift (unsigned int y, ShiftOp z) const
+{
+  return lshift (y, z, bitsize, precision);
+}
+
+/* Left shifting by an wide_int shift amount.  See the definition of
+   Op.TRUNC for how to set Z.  */
+
+wide_int
+wide_int::lshift (const wide_int &y, ShiftOp z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (bitsize, y, TRUNC);
+      if (shift == -1)
+	return wide_int::zero (bitsize, precision);
+      return lshift (shift, NONE, bitsize, precision);
+    }
+  else
+    return lshift (trunc_shift (bitsize, y, NONE), NONE, bitsize, precision);
+}
+
+/* Left shift THIS by CNT.  See the definition of Op.TRUNC for how to
+   set Z.  Since this is used internally, it has the ability to
+   specify the BISIZE and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+wide_int
+wide_int::lshift (unsigned int cnt, ShiftOp op, 
+		  unsigned int bs, unsigned int res_prec) const
+{
+  wide_int result;
+
+  if (op == TRUNC)
+    cnt = trunc_shift (bs, cnt);
+
+  /* Handle the simple case quickly.   */
+  if (res_prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.bitsize = bs;
+      result.precision = res_prec;
+      result.len = 1;
+      result.val[0] = val[0] << cnt;
+    }
+  else
+    result = lshift_large (cnt, bs, res_prec);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s << %d)\n", result, *this, cnt);
+#endif
+
+  return result;
+}
+
+/* Rotate THIS left by Y within its precision.  */
+
+wide_int
+wide_int::lrotate (const wide_int &y) const
+{
+  return lrotate (y.val[0]);
+}
+
+
+/* Unsigned right shift by Y.  See the definition of Op.TRUNC for how
+   to set Z.  */
+
+wide_int
+wide_int::rshiftu (const wide_int &y, ShiftOp z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (bitsize, y, TRUNC);
+      if (shift == -1)
+	return wide_int::zero (bitsize, precision);
+      return rshiftu (shift, NONE);
+    }
+  else
+    return rshiftu (trunc_shift (bitsize, y, NONE), NONE);
+}
+
+/* Right shift THIS by Y.  SGN indicates the sign.  Z indicates the
+   truncation option.  */
+
+wide_int
+wide_int::rshift (const wide_int &y, SignOp sgn, ShiftOp z) const
+{
+  if (sgn == UNSIGNED)
+    return rshiftu (y, z);
+  else
+    return rshifts (y, z);
+}
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set Z.  */
+
+wide_int
+wide_int::rshiftu (unsigned int cnt, ShiftOp trunc_op) const
+{
+  wide_int result;
+
+  if (trunc_op == TRUNC)
+    cnt = trunc_shift (bitsize, cnt);
+
+  if (cnt == 0)
+    result = copy ();
+  
+  else if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* Handle the simple case quickly.   */
+      unsigned HOST_WIDE_INT x = val[0];
+
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.len = 1;
+
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	x = zext_hwi (x, precision);
+
+      result.val[0] = x >> cnt;
+    }
+  else 
+    result = rshiftu_large (cnt);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s >>U %d)\n", result, *this, cnt);
+#endif
+  return result;
+}
+
+/* Signed right shift by Y.  See the definition of Op.TRUNC for how to
+   set Z.  */
+wide_int
+wide_int::rshifts (const wide_int &y, ShiftOp z) const
+{
+  if (z == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (bitsize, y, TRUNC);
+      if (shift == -1)
+	{
+	  /* The value of the shift was larger than the bitsize and this
+	     machine does not truncate the value, so the result is
+	     a smeared sign bit.  */
+	  if (neg_p ())
+	    return wide_int::minus_one (bitsize, precision);
+	  else
+	    return wide_int::zero (bitsize, precision);
+	}
+      return rshifts (shift, NONE);
+    }
+  else
+    return rshifts (trunc_shift (bitsize, y, NONE), NONE);
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set Z.  */
+
+wide_int
+wide_int::rshifts (unsigned int cnt, ShiftOp trunc_op) const
+{
+  wide_int result;
+
+  if (trunc_op == TRUNC)
+    cnt = trunc_shift (bitsize, cnt);
+
+  if (cnt == 0)
+    result = copy ();
+  else if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* Handle the simple case quickly.   */
+      HOST_WIDE_INT x = val[0];
+
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.len = 1;
+      result.val[0] = x >> cnt;
+    }
+  else
+    result = rshifts_large (cnt);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s >>S %d)\n", result, *this, cnt);
+#endif
+  return result;
+}
+
+/* Rotate THIS right by Y within its precision.  */
+
+wide_int
+wide_int::rrotate (const wide_int &y) const
+{
+  return rrotate (y.val[0]);
+}
+
+/* tree related routines.  */
+
+extern tree wide_int_to_tree (tree type, const wide_int &cst);
+extern tree wide_int_to_infinite_tree (tree type, const wide_int &cst, 
+				       unsigned int prec);
+extern tree force_fit_type_wide (tree, const wide_int &, int, bool);
+#if 0
+extern wide_int mem_ref_offset (const_tree);
+#endif
+
+/* Conversion to and from GMP integer representations.  */
+
+void mpz_set_wide_int (mpz_t, wide_int, bool);
+wide_int mpz_get_wide_int (const_tree, mpz_t, bool);
+#endif /* GENERATOR FILE */
+
+#endif /* WIDE_INT_H */

[-- Attachment #3: p4-3.clog --]
[-- Type: text/plain, Size: 242 bytes --]

2013-2-26  Kenneth Zadeck <zadeck@naturalbridge.com>

	* Makefile.in (wide-int.c, wide-int.h): New files.
	* wide-int.c: New file containing implementation of wide_int class.
	* wide-int.h: New file containing public spec for wide_int class.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch - patch ping for the next stage 1
  2013-02-27  0:23                                   ` patch to fix constant math - first small patch - patch ping for the next stage 1 Kenneth Zadeck
@ 2013-03-27 14:13                                     ` Richard Biener
  2013-03-28 15:06                                       ` Kenneth Zadeck
  2013-03-31 17:51                                       ` Kenneth Zadeck
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Biener @ 2013-03-27 14:13 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Joseph S. Myers, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
> Here is the first of my wide int patches with joseph's comments and the
> patch rot removed.
>
> I would like to get these pre approved for the next stage 1.

+      int shift = HOST_BITS_PER_WIDE_INT - (prec &
(HOST_BITS_PER_WIDE_INT - 1));

I think this should gcc_checking_assert that prec is not out of range
(any reason why prec is signed int and not unsigned int?) rather than
ignore bits in prec.

+static inline HOST_WIDE_INT
+zext_hwi (HOST_WIDE_INT src, int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    return src & (((HOST_WIDE_INT)1
+                  << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
+}

likewise.  Also I'm not sure I agree about the signedness of the result / src.
zext_hwi (-1, HOST_BITS_PER_WIDE_INT) < 0 is true which is odd.

The patch misses context of uses, so I'm not sure what the above functions
are intended to do.

Richard.

> On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
>>
>> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>>
>>> +# define HOST_HALF_WIDE_INT_PRINT "h"
>>
>> This may cause problems on hosts not supporting %hd (MinGW?), and there's
>> no real need for using "h" here given the promotion of short to int; you
>> can just use "" (rather than e.g. needing special handling in xm-mingw32.h
>> like is done for HOST_LONG_LONG_FORMAT).
>>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - second small patch -patch ping for next stage 1
  2013-02-27  0:28                                   ` patch to fix constant math - second small patch -patch ping for next stage 1 Kenneth Zadeck
@ 2013-03-27 14:18                                     ` Richard Biener
  2013-03-27 14:23                                       ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-03-27 14:18 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

On Wed, Feb 27, 2013 at 1:27 AM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
> Here is the second of my wide int patches with the patch rot removed.
>
> I would like to get these pre approved for the next stage 1.
> On 10/05/2012 06:48 PM, Kenneth Zadeck wrote:
>>
>> This patch adds machinery to genmodes.c so that largest possible sizes of
>> various data structures can be determined at gcc build time. These functions
>> create 3 symbols that are available in insn-modes.h:
>> MAX_BITSIZE_MODE_INT - the bitsize of the largest int.
>> MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int.
>> MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int.

I remember we have discussed about the need to special-case/handle partial
integer modes.  Do further patches use the _INT and _PARTIAL_INT sizes
at all?  I'm fine with providing MAX_BITSIZE_MODE_ANY_INT.

Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - second small patch -patch ping for next stage 1
  2013-03-27 14:18                                     ` Richard Biener
@ 2013-03-27 14:23                                       ` Kenneth Zadeck
  2013-03-27 15:07                                         ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-03-27 14:23 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor


On 03/27/2013 10:18 AM, Richard Biener wrote:
> On Wed, Feb 27, 2013 at 1:27 AM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> Here is the second of my wide int patches with the patch rot removed.
>>
>> I would like to get these pre approved for the next stage 1.
>> On 10/05/2012 06:48 PM, Kenneth Zadeck wrote:
>>> This patch adds machinery to genmodes.c so that largest possible sizes of
>>> various data structures can be determined at gcc build time. These functions
>>> create 3 symbols that are available in insn-modes.h:
>>> MAX_BITSIZE_MODE_INT - the bitsize of the largest int.
>>> MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int.
>>> MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int.
> I remember we have discussed about the need to special-case/handle partial
> integer modes.  Do further patches use the _INT and _PARTIAL_INT sizes
> at all?  I'm fine with providing MAX_BITSIZE_MODE_ANY_INT.
i do not believe that in the end, those two ended up getting used.    i 
can remove them if you want.

kenny
>
> Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-02-27  1:59                                                                         ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Kenneth Zadeck
@ 2013-03-27 14:54                                                                           ` Richard Biener
  2013-04-04  8:08                                                                             ` Kenneth Zadeck
  2013-04-02 15:40                                                                           ` Richard Biener
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-03-27 14:54 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
> This patch contains a large number of the changes requested by Richi.   It
> does not contain any of the changes that he requested to abstract the
> storage layer.   That suggestion appears to be quite unworkable.
>
> I believe that the wide-int class addresses the needs of gcc for performing
> math on any size integer irregardless of the platform that hosts the
> compiler.  The interface is admittedly large, but it is large for a reason:
> these are the operations that are commonly performed by the client
> optimizations in the compiler.
>
> I would like to get this patch preapproved for the next stage 1.

Please clean from dead code like

+// using wide_int::;

and

+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wh ("wide_int::from_shwi %s " HOST_WIDE_INT_PRINT_HEX ")\n",
+             result, op0);
+#endif

and

+#ifdef NEW_REP_FOR_INT_CST
+  /* This is the code once the tree level is converted.  */
+  wide_int result;
+  int i;
+
+  tree type = TREE_TYPE (tcst);
+
+  result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
+  result.precision = TYPE_PRECISION (type);
+  result.len = TREE_INT_CST_LEN (tcst);
+  for (i = 0; i < result.len; i++)
+    result.val[i] = TREE_INT_CST_ELT (tcst, i);
+
+  return result;
+#else

this also shows the main reason I was asking for storage abstraction.
The initialization from tree is way too expensive.

+/* Convert a integer cst into a wide int expanded to BITSIZE and
+   PRECISION.  This call is used by tree passes like vrp that expect
+   that the math is done in an infinite precision style.  BITSIZE and
+   PRECISION are generally determined to be twice the largest type
+   seen in the function.  */
+
+wide_int
+wide_int::from_tree_as_infinite_precision (const_tree tcst,
+                                          unsigned int bitsize,
+                                          unsigned int precision)
+{

I know you have converted everything, but to make this patch reviewable
I'd like you to strip the initial wide_int down to a bare minimum.

Only then people will have a reasonable chance to play with interface
changes (such as providing a storage abstraction).

+/* Check the upper HOST_WIDE_INTs of src to see if the length can be
+   shortened.  An upper HOST_WIDE_INT is unnecessary if it is all ones
+   or zeros and the top bit of the next lower word matches.
+
+   This function may change the representation of THIS, but does not
+   change the value that THIS represents.  It does not sign extend in
+   the case that the size of the mode is less than
+   HOST_BITS_PER_WIDE_INT.  */
+
+void
+wide_int::canonize ()

this shouldn't be necessary - it's an optimization - and due to value
semantics (yes - I know you have a weird mix of value semantics
and modify-in-place in wide_int) the new length should be computed
transparently when creating a new value.

Well.  Leaving wide-int.c for now.

+class wide_int {
+  /* Internal representation.  */
+
+  /* VAL is set to a size that is capable of computing a full
+     multiplication on the largest mode that is represented on the
+     target.  The full multiplication is use by tree-vrp.  tree-vpn
+     currently does a 2x largest mode by 2x largest mode yielding a 4x
+     largest mode result.  If operations are added that require larger
+     buffers, then VAL needs to be changed.  */
+  HOST_WIDE_INT val[4 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];

as you conver partial int modes in MAX_BITSIZE_MODE_ANY_INT the
above may come too short.  Please properly round up.

+  unsigned short len;
+  unsigned int bitsize;
+  unsigned int precision;

I see we didn't get away with this mix of bitsize and precision.  I'm probably
going to try revisit the past discussions - but can you point me to a single
place in the RTL conversion where they make a difference?  Bits beyond
precision are either undefined or properly zero-/sign-extended.  Implicit
extension beyond len val members should then provide in "valid" bits
up to bitsize (if anyone cares).  That's how double-ints work on tree
INTGER_CSTs
which only care for precision, even with partial integer mode types
(ok, I never came along one of these beasts - testcase / target?).

[abstraction possibility - have both wide_ints with actual mode and
wide_ints with arbitrary bitsize/precision]

+  enum ShiftOp {
+    NONE,
+    /* There are two uses for the wide-int shifting functions.  The
+       first use is as an emulation of the target hardware.  The
+       second use is as service routines for other optimizations.  The
+       first case needs to be identified by passing TRUNC as the value
+       of ShiftOp so that shift amount is properly handled according to the
+       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
+       amount is always truncated by the bytesize of the mode of
+       THIS.  */
+    TRUNC
+  };

I think I have expressed my opinion on this.  (and SHIFT_COUNT_TRUNCATED
should vanish - certainly wide-int shouldn't care, so doesn't double-int)

+  enum SignOp {
+    /* Many of the math functions produce different results depending
+       on if they are SIGNED or UNSIGNED.  In general, there are two
+       different functions, whose names are prefixed with an 'S" and
+       or an 'U'.  However, for some math functions there is also a
+       routine that does not have the prefix and takes an SignOp
+       parameter of SIGNED or UNSIGNED.  */
+    SIGNED,
+    UNSIGNED
+  };

See above.  GCC standard practice is a 'unsigned uns' parameter.

+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type);
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type,
+                                  bool *overflow);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode,
+                                   bool *overflow);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0,
+                                   enum machine_mode mode);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0,
+                                   enum machine_mode mode,
+                                   bool *overflow);

way too many overloads.  Besides the "raw" ones I only expect wide-ints
to be constructed from a tree INTEGER_CST or a rtx DOUBLE_INT.

+  inline static wide_int minus_one (unsigned int bitsize, unsigned int prec);
+  inline static wide_int minus_one (const_tree type);
+  inline static wide_int minus_one (enum machine_mode mode);
+  inline static wide_int minus_one (const wide_int &op1);

wide-ints representation should be properly sign-extended, thus all of the
possible -1 variants have the same representation.  If it were not for
providing precision and bitsize for which you have the four overloads.
Just have one.  Providing precision (or bitsize).

I see that for example in wide_int::add bitsize and precision are arbitrarily
copied from the first operand.  With the present way of dealing with them
it would sound more logical to assert that they are the same for both
operands (do both need to match?).  I'd rather see wide-int being
"arbitrary" precision/bitsize up to its supported storage size (as
double-int is).
I suppose we've been there and discussed this to death already though ;)
As you have some fused operation plus sign-/zero-extend ops already
the alternative is to always provide a precision for the result and treat the
operands as "arbitrary" precision (that way wide_int::minus_one can
simply return a sign-extended precision 1 -1).

Btw, wide_int::add does not look at bitsize at all, so it clearly is redundant
information.  Grepping for uses of bitsize shows up only maintaining and
copying around this information as well.  please remove bitsize.

Ok, enough for today.

Thanks,
Richard.

> kenny
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - second small patch -patch ping for next stage 1
  2013-03-27 14:23                                       ` Kenneth Zadeck
@ 2013-03-27 15:07                                         ` Richard Biener
  2013-03-28 14:47                                           ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-03-27 15:07 UTC (permalink / raw)
  To: Kenneth Zadeck; +Cc: Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

On Wed, Mar 27, 2013 at 3:23 PM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
>
> On 03/27/2013 10:18 AM, Richard Biener wrote:
>>
>> On Wed, Feb 27, 2013 at 1:27 AM, Kenneth Zadeck
>> <zadeck@naturalbridge.com> wrote:
>>>
>>> Here is the second of my wide int patches with the patch rot removed.
>>>
>>> I would like to get these pre approved for the next stage 1.
>>> On 10/05/2012 06:48 PM, Kenneth Zadeck wrote:
>>>>
>>>> This patch adds machinery to genmodes.c so that largest possible sizes
>>>> of
>>>> various data structures can be determined at gcc build time. These
>>>> functions
>>>> create 3 symbols that are available in insn-modes.h:
>>>> MAX_BITSIZE_MODE_INT - the bitsize of the largest int.
>>>> MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int.
>>>> MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int.
>>
>> I remember we have discussed about the need to special-case/handle partial
>> integer modes.  Do further patches use the _INT and _PARTIAL_INT sizes
>> at all?  I'm fine with providing MAX_BITSIZE_MODE_ANY_INT.
>
> i do not believe that in the end, those two ended up getting used.    i can
> remove them if you want.

Yes please.  Ok with that change.

Richard.

> kenny
>>
>>
>> Richard.
>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - second small patch -patch ping for next stage 1
  2013-03-27 15:07                                         ` Richard Biener
@ 2013-03-28 14:47                                           ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-03-28 14:47 UTC (permalink / raw)
  To: Richard Biener; +Cc: Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

committed as revision 197200.

kenny


On 03/27/2013 11:07 AM, Richard Biener wrote:
> On Wed, Mar 27, 2013 at 3:23 PM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> On 03/27/2013 10:18 AM, Richard Biener wrote:
>>> On Wed, Feb 27, 2013 at 1:27 AM, Kenneth Zadeck
>>> <zadeck@naturalbridge.com> wrote:
>>>> Here is the second of my wide int patches with the patch rot removed.
>>>>
>>>> I would like to get these pre approved for the next stage 1.
>>>> On 10/05/2012 06:48 PM, Kenneth Zadeck wrote:
>>>>> This patch adds machinery to genmodes.c so that largest possible sizes
>>>>> of
>>>>> various data structures can be determined at gcc build time. These
>>>>> functions
>>>>> create 3 symbols that are available in insn-modes.h:
>>>>> MAX_BITSIZE_MODE_INT - the bitsize of the largest int.
>>>>> MAX_BITSIZE_MODE_PARTIAL_INT - the bitsize of the largest partial int.
>>>>> MAX_BITSIZE_MODE_ANY_INT - the largest bitsize of any kind of int.
>>> I remember we have discussed about the need to special-case/handle partial
>>> integer modes.  Do further patches use the _INT and _PARTIAL_INT sizes
>>> at all?  I'm fine with providing MAX_BITSIZE_MODE_ANY_INT.
>> i do not believe that in the end, those two ended up getting used.    i can
>> remove them if you want.
> Yes please.  Ok with that change.
>
> Richard.
>
>> kenny
>>>
>>> Richard.
>>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch - patch ping for the next stage 1
  2013-03-27 14:13                                     ` Richard Biener
@ 2013-03-28 15:06                                       ` Kenneth Zadeck
  2013-03-31 17:51                                       ` Kenneth Zadeck
  1 sibling, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-03-28 15:06 UTC (permalink / raw)
  To: Richard Biener
  Cc: Joseph S. Myers, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

richard,

adding the gcc_checking_assert is going to require that i include 
system.h in hwint.h which seems to cause a loop.  while in principle, i 
agree with the assert, this is going to be a mess.

kenny


On 03/27/2013 10:13 AM, Richard Biener wrote:
> On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> Here is the first of my wide int patches with joseph's comments and the
>> patch rot removed.
>>
>> I would like to get these pre approved for the next stage 1.
> +      int shift = HOST_BITS_PER_WIDE_INT - (prec &
> (HOST_BITS_PER_WIDE_INT - 1));
>
> I think this should gcc_checking_assert that prec is not out of range
> (any reason why prec is signed int and not unsigned int?) rather than
> ignore bits in prec.
>
> +static inline HOST_WIDE_INT
> +zext_hwi (HOST_WIDE_INT src, int prec)
> +{
> +  if (prec == HOST_BITS_PER_WIDE_INT)
> +    return src;
> +  else
> +    return src & (((HOST_WIDE_INT)1
> +                  << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
> +}
>
> likewise.  Also I'm not sure I agree about the signedness of the result / src.
> zext_hwi (-1, HOST_BITS_PER_WIDE_INT) < 0 is true which is odd.
>
> The patch misses context of uses, so I'm not sure what the above functions
> are intended to do.
>
> Richard.
>
>> On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
>>> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>>>
>>>> +# define HOST_HALF_WIDE_INT_PRINT "h"
>>> This may cause problems on hosts not supporting %hd (MinGW?), and there's
>>> no real need for using "h" here given the promotion of short to int; you
>>> can just use "" (rather than e.g. needing special handling in xm-mingw32.h
>>> like is done for HOST_LONG_LONG_FORMAT).
>>>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch - patch ping for the next stage 1
  2013-03-27 14:13                                     ` Richard Biener
  2013-03-28 15:06                                       ` Kenneth Zadeck
@ 2013-03-31 17:51                                       ` Kenneth Zadeck
  2013-04-02  9:45                                         ` Richard Biener
  1 sibling, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-03-31 17:51 UTC (permalink / raw)
  To: Richard Biener
  Cc: Joseph S. Myers, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 2206 bytes --]

richard,

I was able to add everything except for the checking asserts.    While I 
think that this is a reasonable idea, it is difficult to add that to a 
function that is defined in hwint.h because of circular includes.   I 
could move this another file (though this appears to be the logical 
correct place for it), or we can do without the asserts.

The context is that [sz]ext_hwi is that are used are over the compiler 
but are generally written out long.   The wide-int class uses them also, 
but wide-int did not see like the right place for them to live and i 
believe that you suggested that i move them.

ok to commit, or do you have a suggested resolution to the assert issue?

kenny


On 03/27/2013 10:13 AM, Richard Biener wrote:
> On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> Here is the first of my wide int patches with joseph's comments and the
>> patch rot removed.
>>
>> I would like to get these pre approved for the next stage 1.
> +      int shift = HOST_BITS_PER_WIDE_INT - (prec &
> (HOST_BITS_PER_WIDE_INT - 1));
>
> I think this should gcc_checking_assert that prec is not out of range
> (any reason why prec is signed int and not unsigned int?) rather than
> ignore bits in prec.
>
> +static inline HOST_WIDE_INT
> +zext_hwi (HOST_WIDE_INT src, int prec)
> +{
> +  if (prec == HOST_BITS_PER_WIDE_INT)
> +    return src;
> +  else
> +    return src & (((HOST_WIDE_INT)1
> +                  << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
> +}
>
> likewise.  Also I'm not sure I agree about the signedness of the result / src.
> zext_hwi (-1, HOST_BITS_PER_WIDE_INT) < 0 is true which is odd.
>
> The patch misses context of uses, so I'm not sure what the above functions
> are intended to do.
>
> Richard.
>
>> On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
>>> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>>>
>>>> +# define HOST_HALF_WIDE_INT_PRINT "h"
>>> This may cause problems on hosts not supporting %hd (MinGW?), and there's
>>> no real need for using "h" here given the promotion of short to int; you
>>> can just use "" (rather than e.g. needing special handling in xm-mingw32.h
>>> like is done for HOST_LONG_LONG_FORMAT).
>>>


[-- Attachment #2: p1-4.diff --]
[-- Type: text/x-patch, Size: 4092 bytes --]

diff --git a/gcc/hwint.h b/gcc/hwint.h
index da62fad..b086af0 100644
--- a/gcc/hwint.h
+++ b/gcc/hwint.h
@@ -76,6 +76,40 @@ extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1];
 # endif
 #endif
 
+/* Print support for half a host wide int.  */
+#define HOST_BITS_PER_HALF_WIDE_INT (HOST_BITS_PER_WIDE_INT / 2)
+#if HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_LONG
+# define HOST_HALF_WIDE_INT long
+# define HOST_HALF_WIDE_INT_PRINT HOST_LONG_FORMAT
+# define HOST_HALF_WIDE_INT_PRINT_C "L"
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_INT
+# define HOST_HALF_WIDE_INT int
+# define HOST_HALF_WIDE_INT_PRINT ""
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_SHORT
+# define HOST_HALF_WIDE_INT short
+# define HOST_HALF_WIDE_INT_PRINT ""
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#else
+#error Please add support for HOST_HALF_WIDE_INT
+#endif
+
+
 #define HOST_WIDE_INT_1 HOST_WIDE_INT_C(1)
 
 /* This is a magic identifier which allows GCC to figure out the type
@@ -93,9 +127,13 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
 # if HOST_BITS_PER_WIDE_INT == 64
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%016" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%016" HOST_LONG_FORMAT "x"
 # else
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%08" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%08" HOST_LONG_FORMAT "x"
 # endif
 #else
 # define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT
@@ -103,6 +141,8 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
   /* We can assume that 'long long' is at least 64 bits.  */
 # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
     "0x%" HOST_LONG_LONG_FORMAT "x%016" HOST_LONG_LONG_FORMAT "x"
+# define HOST_WIDE_INT_PRINT_PADDED_HEX \
+    "%016" HOST_LONG_LONG_FORMAT "x"
 #endif /* HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG */
 
 #define HOST_WIDE_INT_PRINT_DEC "%" HOST_WIDE_INT_PRINT "d"
@@ -276,4 +316,31 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT);
 
+/* Sign extend SRC starting from PREC.  */
+
+static inline HOST_WIDE_INT
+sext_hwi (HOST_WIDE_INT src, unsigned int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    {
+      int shift = HOST_BITS_PER_WIDE_INT - 
+	(prec & (HOST_BITS_PER_WIDE_INT - 1));
+      return (src << shift) >> shift;
+    }
+}
+
+/* Zero extend SRC starting from PREC.  */
+
+static inline unsigned HOST_WIDE_INT
+zext_hwi (unsigned HOST_WIDE_INT src, unsigned int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    return src & (((HOST_WIDE_INT)1
+		   << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
+}
+
 #endif /* ! GCC_HWINT_H */

[-- Attachment #3: p1-4.clog --]
[-- Type: text/plain, Size: 389 bytes --]

2013-3-31  Kenneth Zadeck <zadeck@naturalbridge.com>

	* hwint.h (HOST_BITS_PER_HALF_WIDE_INT, HOST_HALF_WIDE_INT,
	HOST_HALF_WIDE_INT_PRINT, HOST_HALF_WIDE_INT_PRINT_C,
	HOST_HALF_WIDE_INT_PRINT_DEC, HOST_HALF_WIDE_INT_PRINT_DEC_C,
	HOST_HALF_WIDE_INT_PRINT_UNSIGNED, HOST_HALF_WIDE_INT_PRINT_HEX,
	HOST_HALF_WIDE_INT_PRINT_HEX_PURE): New symbols.
	(sext_hwi, zext_hwi): New functions.
	

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch - patch ping for the next stage 1
  2013-03-31 17:51                                       ` Kenneth Zadeck
@ 2013-04-02  9:45                                         ` Richard Biener
  2013-04-02 14:34                                           ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-02  9:45 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Joseph S. Myers, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
> richard,
>
> I was able to add everything except for the checking asserts.    While I
> think that this is a reasonable idea, it is difficult to add that to a
> function that is defined in hwint.h because of circular includes.   I could
> move this another file (though this appears to be the logical correct place
> for it), or we can do without the asserts.
>
> The context is that [sz]ext_hwi is that are used are over the compiler but
> are generally written out long.   The wide-int class uses them also, but
> wide-int did not see like the right place for them to live and i believe
> that you suggested that i move them.
>
> ok to commit, or do you have a suggested resolution to the assert issue?

Yes, do

#ifdef ENABLE_CHECKING
extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
#else
+/* Sign extend SRC starting from PREC.  */
+
+static inline HOST_WIDE_INT
+sext_hwi (HOST_WIDE_INT src, unsigned int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    {
        int shift = HOST_BITS_PER_WIDE_INT - prec;
+      return (src << shift) >> shift;
+    }
+}
#endif

and for ENABLE_CHECKING only provide an out-of-line implementation
in hwint.c.  That's how we did it with abs_hwi (well, we just do not provide
an inline variant there - that's another possibility).

Note that hwint.h is always included after config.h so the ENABLE_CHECKING
definition should be available.

Richard.

>
> kenny
>
>
> On 03/27/2013 10:13 AM, Richard Biener wrote:
>>
>> On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck
>> <zadeck@naturalbridge.com> wrote:
>>>
>>> Here is the first of my wide int patches with joseph's comments and the
>>> patch rot removed.
>>>
>>> I would like to get these pre approved for the next stage 1.
>>
>> +      int shift = HOST_BITS_PER_WIDE_INT - (prec &
>> (HOST_BITS_PER_WIDE_INT - 1));
>>
>> I think this should gcc_checking_assert that prec is not out of range
>> (any reason why prec is signed int and not unsigned int?) rather than
>> ignore bits in prec.
>>
>> +static inline HOST_WIDE_INT
>> +zext_hwi (HOST_WIDE_INT src, int prec)
>> +{
>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>> +    return src;
>> +  else
>> +    return src & (((HOST_WIDE_INT)1
>> +                  << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
>> +}
>>
>> likewise.  Also I'm not sure I agree about the signedness of the result /
>> src.
>> zext_hwi (-1, HOST_BITS_PER_WIDE_INT) < 0 is true which is odd.
>>
>> The patch misses context of uses, so I'm not sure what the above functions
>> are intended to do.
>>
>> Richard.
>>
>>> On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
>>>>
>>>> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>>>>
>>>>> +# define HOST_HALF_WIDE_INT_PRINT "h"
>>>>
>>>> This may cause problems on hosts not supporting %hd (MinGW?), and
>>>> there's
>>>> no real need for using "h" here given the promotion of short to int; you
>>>> can just use "" (rather than e.g. needing special handling in
>>>> xm-mingw32.h
>>>> like is done for HOST_LONG_LONG_FORMAT).
>>>>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch - patch ping for the next stage 1
  2013-04-02  9:45                                         ` Richard Biener
@ 2013-04-02 14:34                                           ` Kenneth Zadeck
  2013-04-02 15:29                                             ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-02 14:34 UTC (permalink / raw)
  To: Richard Biener
  Cc: Joseph S. Myers, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 3361 bytes --]

Richard,

did everything that you asked here.  bootstrapped and regtested on 
x86-64.  ok to commit?

kenny

On 04/02/2013 05:38 AM, Richard Biener wrote:
> On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> richard,
>>
>> I was able to add everything except for the checking asserts.    While I
>> think that this is a reasonable idea, it is difficult to add that to a
>> function that is defined in hwint.h because of circular includes.   I could
>> move this another file (though this appears to be the logical correct place
>> for it), or we can do without the asserts.
>>
>> The context is that [sz]ext_hwi is that are used are over the compiler but
>> are generally written out long.   The wide-int class uses them also, but
>> wide-int did not see like the right place for them to live and i believe
>> that you suggested that i move them.
>>
>> ok to commit, or do you have a suggested resolution to the assert issue?
> Yes, do
>
> #ifdef ENABLE_CHECKING
> extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
> #else
> +/* Sign extend SRC starting from PREC.  */
> +
> +static inline HOST_WIDE_INT
> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
> +{
> +  if (prec == HOST_BITS_PER_WIDE_INT)
> +    return src;
> +  else
> +    {
>          int shift = HOST_BITS_PER_WIDE_INT - prec;
> +      return (src << shift) >> shift;
> +    }
> +}
> #endif
>
> and for ENABLE_CHECKING only provide an out-of-line implementation
> in hwint.c.  That's how we did it with abs_hwi (well, we just do not provide
> an inline variant there - that's another possibility).
>
> Note that hwint.h is always included after config.h so the ENABLE_CHECKING
> definition should be available.
>
> Richard.
>
>> kenny
>>
>>
>> On 03/27/2013 10:13 AM, Richard Biener wrote:
>>> On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck
>>> <zadeck@naturalbridge.com> wrote:
>>>> Here is the first of my wide int patches with joseph's comments and the
>>>> patch rot removed.
>>>>
>>>> I would like to get these pre approved for the next stage 1.
>>> +      int shift = HOST_BITS_PER_WIDE_INT - (prec &
>>> (HOST_BITS_PER_WIDE_INT - 1));
>>>
>>> I think this should gcc_checking_assert that prec is not out of range
>>> (any reason why prec is signed int and not unsigned int?) rather than
>>> ignore bits in prec.
>>>
>>> +static inline HOST_WIDE_INT
>>> +zext_hwi (HOST_WIDE_INT src, int prec)
>>> +{
>>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>>> +    return src;
>>> +  else
>>> +    return src & (((HOST_WIDE_INT)1
>>> +                  << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
>>> +}
>>>
>>> likewise.  Also I'm not sure I agree about the signedness of the result /
>>> src.
>>> zext_hwi (-1, HOST_BITS_PER_WIDE_INT) < 0 is true which is odd.
>>>
>>> The patch misses context of uses, so I'm not sure what the above functions
>>> are intended to do.
>>>
>>> Richard.
>>>
>>>> On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
>>>>> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>>>>>
>>>>>> +# define HOST_HALF_WIDE_INT_PRINT "h"
>>>>> This may cause problems on hosts not supporting %hd (MinGW?), and
>>>>> there's
>>>>> no real need for using "h" here given the promotion of short to int; you
>>>>> can just use "" (rather than e.g. needing special handling in
>>>>> xm-mingw32.h
>>>>> like is done for HOST_LONG_LONG_FORMAT).
>>>>>


[-- Attachment #2: p1-5.clog --]
[-- Type: text/plain, Size: 437 bytes --]

2013-4-02  Kenneth Zadeck <zadeck@naturalbridge.com>

	* hwint.c (sext_hwi, zext_hwi): New functions.
	* hwint.h (HOST_BITS_PER_HALF_WIDE_INT, HOST_HALF_WIDE_INT,
	HOST_HALF_WIDE_INT_PRINT, HOST_HALF_WIDE_INT_PRINT_C,
	HOST_HALF_WIDE_INT_PRINT_DEC, HOST_HALF_WIDE_INT_PRINT_DEC_C,
	HOST_HALF_WIDE_INT_PRINT_UNSIGNED, HOST_HALF_WIDE_INT_PRINT_HEX,
	HOST_HALF_WIDE_INT_PRINT_HEX_PURE): New symbols.
	(sext_hwi, zext_hwi): New functions.
	

[-- Attachment #3: p1-5.diff --]
[-- Type: text/x-patch, Size: 5323 bytes --]

diff --git a/gcc/hwint.c b/gcc/hwint.c
index 330b42c..7e5b85c 100644
--- a/gcc/hwint.c
+++ b/gcc/hwint.c
@@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b)
 {
   return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b));
 }
+
+#ifndef ENABLE_CHECKING
+/* Sign extend SRC starting from PREC.  */
+
+HOST_WIDE_INT
+sext_hwi (HOST_WIDE_INT src, unsigned int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    {
+      int shift = HOST_BITS_PER_WIDE_INT - 
+	(prec & (HOST_BITS_PER_WIDE_INT - 1));
+      return (src << shift) >> shift;
+    }
+}
+
+/* Zero extend SRC starting from PREC.  */
+
+unsigned HOST_WIDE_INT
+zext_hwi (unsigned HOST_WIDE_INT src, unsigned int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    return src & (((HOST_WIDE_INT)1
+		   << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
+}
+
+#endif
diff --git a/gcc/hwint.h b/gcc/hwint.h
index da62fad..9dddf05 100644
--- a/gcc/hwint.h
+++ b/gcc/hwint.h
@@ -76,6 +76,40 @@ extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1];
 # endif
 #endif
 
+/* Print support for half a host wide int.  */
+#define HOST_BITS_PER_HALF_WIDE_INT (HOST_BITS_PER_WIDE_INT / 2)
+#if HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_LONG
+# define HOST_HALF_WIDE_INT long
+# define HOST_HALF_WIDE_INT_PRINT HOST_LONG_FORMAT
+# define HOST_HALF_WIDE_INT_PRINT_C "L"
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_INT
+# define HOST_HALF_WIDE_INT int
+# define HOST_HALF_WIDE_INT_PRINT ""
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_SHORT
+# define HOST_HALF_WIDE_INT short
+# define HOST_HALF_WIDE_INT_PRINT ""
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#else
+#error Please add support for HOST_HALF_WIDE_INT
+#endif
+
+
 #define HOST_WIDE_INT_1 HOST_WIDE_INT_C(1)
 
 /* This is a magic identifier which allows GCC to figure out the type
@@ -93,9 +127,13 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
 # if HOST_BITS_PER_WIDE_INT == 64
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%016" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%016" HOST_LONG_FORMAT "x"
 # else
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%08" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%08" HOST_LONG_FORMAT "x"
 # endif
 #else
 # define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT
@@ -103,6 +141,8 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
   /* We can assume that 'long long' is at least 64 bits.  */
 # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
     "0x%" HOST_LONG_LONG_FORMAT "x%016" HOST_LONG_LONG_FORMAT "x"
+# define HOST_WIDE_INT_PRINT_PADDED_HEX \
+    "%016" HOST_LONG_LONG_FORMAT "x"
 #endif /* HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG */
 
 #define HOST_WIDE_INT_PRINT_DEC "%" HOST_WIDE_INT_PRINT "d"
@@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT);
 
+/* Sign extend SRC starting from PREC.  */
+
+#ifdef ENABLE_CHECKING
+extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
+#else
+static inline HOST_WIDE_INT
+sext_hwi (HOST_WIDE_INT src, unsigned int prec)
+{
+  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
+
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    {
+      int shift = HOST_BITS_PER_WIDE_INT - 
+	(prec & (HOST_BITS_PER_WIDE_INT - 1));
+      return (src << shift) >> shift;
+    }
+}
+#endif
+
+/* Zero extend SRC starting from PREC.  */
+#ifdef ENABLE_CHECKING
+extern unsigned HOST_WIDE_INT zext_hwi (unsigned HOST_WIDE_INT, unsigned int);
+#else
+static inline unsigned HOST_WIDE_INT
+zext_hwi (unsigned HOST_WIDE_INT src, unsigned int prec)
+{
+  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
+
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    return src & (((HOST_WIDE_INT)1
+		   << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
+}
+#endif
+
 #endif /* ! GCC_HWINT_H */

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch - patch ping for the next stage 1
  2013-04-02 14:34                                           ` Kenneth Zadeck
@ 2013-04-02 15:29                                             ` Richard Biener
  2013-04-02 22:43                                               ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-02 15:29 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Joseph S. Myers, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

On Tue, Apr 2, 2013 at 3:49 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> Richard,
>
> did everything that you asked here.  bootstrapped and regtested on x86-64.
> ok to commit?

diff --git a/gcc/hwint.c b/gcc/hwint.c
index 330b42c..7e5b85c 100644
--- a/gcc/hwint.c
+++ b/gcc/hwint.c
@@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b)
 {
   return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b));
 }
+
+#ifndef ENABLE_CHECKING
+/* Sign extend SRC starting from PREC.  */
+
+HOST_WIDE_INT
+sext_hwi (HOST_WIDE_INT src, unsigned int prec)

this should go to hwint.h, and without the masking of prec.
while ...

diff --git a/gcc/hwint.h b/gcc/hwint.h
index da62fad..9dddf05 100644
--- a/gcc/hwint.h
+++ b/gcc/hwint.h
@@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT,
HOST_WIDE_INT);
 extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT);

+/* Sign extend SRC starting from PREC.  */
+
+#ifdef ENABLE_CHECKING
+extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
+#else
+static inline HOST_WIDE_INT
+sext_hwi (HOST_WIDE_INT src, unsigned int prec)
+{
+  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);

this should go to hwint.c (also without masking prec).

Richard.




> kenny
>
>
> On 04/02/2013 05:38 AM, Richard Biener wrote:
>>
>> On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck
>> <zadeck@naturalbridge.com> wrote:
>>>
>>> richard,
>>>
>>> I was able to add everything except for the checking asserts.    While I
>>> think that this is a reasonable idea, it is difficult to add that to a
>>> function that is defined in hwint.h because of circular includes.   I
>>> could
>>> move this another file (though this appears to be the logical correct
>>> place
>>> for it), or we can do without the asserts.
>>>
>>> The context is that [sz]ext_hwi is that are used are over the compiler
>>> but
>>> are generally written out long.   The wide-int class uses them also, but
>>> wide-int did not see like the right place for them to live and i believe
>>> that you suggested that i move them.
>>>
>>> ok to commit, or do you have a suggested resolution to the assert issue?
>>
>> Yes, do
>>
>> #ifdef ENABLE_CHECKING
>> extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
>> #else
>> +/* Sign extend SRC starting from PREC.  */
>> +
>> +static inline HOST_WIDE_INT
>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>> +{
>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>> +    return src;
>> +  else
>> +    {
>>          int shift = HOST_BITS_PER_WIDE_INT - prec;
>> +      return (src << shift) >> shift;
>> +    }
>> +}
>> #endif
>>
>> and for ENABLE_CHECKING only provide an out-of-line implementation
>> in hwint.c.  That's how we did it with abs_hwi (well, we just do not
>> provide
>> an inline variant there - that's another possibility).
>>
>> Note that hwint.h is always included after config.h so the ENABLE_CHECKING
>> definition should be available.
>>
>> Richard.
>>
>>> kenny
>>>
>>>
>>> On 03/27/2013 10:13 AM, Richard Biener wrote:
>>>>
>>>> On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck
>>>> <zadeck@naturalbridge.com> wrote:
>>>>>
>>>>> Here is the first of my wide int patches with joseph's comments and the
>>>>> patch rot removed.
>>>>>
>>>>> I would like to get these pre approved for the next stage 1.
>>>>
>>>> +      int shift = HOST_BITS_PER_WIDE_INT - (prec &
>>>> (HOST_BITS_PER_WIDE_INT - 1));
>>>>
>>>> I think this should gcc_checking_assert that prec is not out of range
>>>> (any reason why prec is signed int and not unsigned int?) rather than
>>>> ignore bits in prec.
>>>>
>>>> +static inline HOST_WIDE_INT
>>>> +zext_hwi (HOST_WIDE_INT src, int prec)
>>>> +{
>>>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>>>> +    return src;
>>>> +  else
>>>> +    return src & (((HOST_WIDE_INT)1
>>>> +                  << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
>>>> +}
>>>>
>>>> likewise.  Also I'm not sure I agree about the signedness of the result
>>>> /
>>>> src.
>>>> zext_hwi (-1, HOST_BITS_PER_WIDE_INT) < 0 is true which is odd.
>>>>
>>>> The patch misses context of uses, so I'm not sure what the above
>>>> functions
>>>> are intended to do.
>>>>
>>>> Richard.
>>>>
>>>>> On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
>>>>>>
>>>>>> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>>>>>>
>>>>>>> +# define HOST_HALF_WIDE_INT_PRINT "h"
>>>>>>
>>>>>> This may cause problems on hosts not supporting %hd (MinGW?), and
>>>>>> there's
>>>>>> no real need for using "h" here given the promotion of short to int;
>>>>>> you
>>>>>> can just use "" (rather than e.g. needing special handling in
>>>>>> xm-mingw32.h
>>>>>> like is done for HOST_LONG_LONG_FORMAT).
>>>>>>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-02-27  1:59                                                                         ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Kenneth Zadeck
  2013-03-27 14:54                                                                           ` Richard Biener
@ 2013-04-02 15:40                                                                           ` Richard Biener
  2013-04-02 19:23                                                                             ` Kenneth Zadeck
  2013-04-05 15:05                                                                             ` Kenneth Zadeck
  1 sibling, 2 replies; 217+ messages in thread
From: Richard Biener @ 2013-04-02 15:40 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 2135 bytes --]

On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
> This patch contains a large number of the changes requested by Richi.   It
> does not contain any of the changes that he requested to abstract the
> storage layer.   That suggestion appears to be quite unworkable.

I of course took this claim as a challenge ... with the following result.  It is
of course quite workable ;)

The attached patch implements the core wide-int class and three storage
models (fixed size for things like plain HWI and double-int, variable size
similar to how your wide-int works and an adaptor for the double-int as
contained in trees).  With that you can now do

HOST_WIDE_INT
wi_test (tree x)
{
  // template argument deduction doesn't do the magic we want it to do
  // to make this kind of implicit conversions work
  // overload resolution considers this kind of conversions so we
  // need some magic that combines both ... but seeding the overload
  // set with some instantiations doesn't seem to be possible :/
  // wide_int<> w = x + 1;
  wide_int<> w;
  w += x;
  w += 1;
  // template argument deduction doesn't deduce the return value type,
  // not considering the template default argument either ...
  // w = wi (x) + 1;
  // we could support this by providing rvalue-to-lvalue promotion
  // via a traits class?
  // otoh it would lead to sub-optimal code anyway so we should
  // make the result available as reference parameter and only support
  // wide_int <> res; add (res, x, 1); ?
  w = wi (x).operator+<wide_int<> >(1);
  wide_int<>::add(w, x, 1);
  return w.to_hwi ();
}

we are somewhat limited with C++ unless we want to get really fancy.
Eventually providing operator+ just doesn't make much sense for
generic wide-int combinations (though then the issue is its operands
are no longer commutative which I think is the case with your wide-int
or double-int as well - they don't suport "1 + wide_int" for obvious reasons).

So there are implementation design choices left undecided.

Oh, and the operation implementations are crap (they compute nonsense).

But you should get the idea.

Richard.

[-- Attachment #2: my-wide-int.c --]
[-- Type: text/x-csrc, Size: 9147 bytes --]

#include "config.h"
#include "system.h"

#include "coretypes.h"
#include "hwint.h"
#include "tree.h"


/* ???  wide-int should probably use HOST_WIDEST_FAST_INT as storage,
   not HOST_WIDE_INT.  Yeah, we could even template on that ...  */

/* Fixed-length embedded storage.  wi_embed<2> is double-int,
   wi_embed<1> is a plain HOST_WIDE_INT.  Can be used for
   small fixed-(minimum)-size calculations on hosts that have
   no suitable integer type.  */

template <unsigned sz>
class wi_embed
{
private:
  HOST_WIDE_INT s[sz];

public:
  void construct () {}
  HOST_WIDE_INT* storage() { return s; }
  const HOST_WIDE_INT* storage() const { return s; }
  unsigned len() const { return sz; }
  void set_len(unsigned l) { gcc_checking_assert (l <= sz); }
};


/* Fixed maximum-length embedded storage but variable dynamic size.  */

//#define MAXSZ (4 * (MAX_MODE_INT_SIZE / HOST_BITS_PER_WIDE_INT))
#define MAXSZ 8

template <unsigned max_sz>
class wi_embed_var
{
private:
  unsigned len_;
  HOST_WIDE_INT s[max_sz];

public:
  void construct () { len_ = 0; }
  HOST_WIDE_INT* storage() { return s; }
  const HOST_WIDE_INT* storage() const { return s; }
  unsigned len() const { return len_; }
  void set_len(unsigned l) { len_ =  l; }
};


/* The wide-int class.  Defaults to variable-length storage
   (alternatively use a typedef to avoid the need to use wide_int <>).  */

template <class S = wi_embed_var<MAXSZ> >
class wide_int;


/* Avoid constructors / destructors to make sure this is a C++04 POD.  */

/* Basic wide_int class.  The storage model allows for rvalue
   storage abstraction avoiding copying from for example tree
   or RTX and to avoid the need of explicit construction for
   integral arguments of up to HWI size.

   A storage model needs to provide the following methods:
    - construct (), default-initialize the storage
    - unsigned len () const, the size of the storage in HWI quantities
    - const HOST_WIDE_INT *storage () const, return a pointer
      to read-only HOST_WIDE_INT storage of size len ().
    - HOST_WIDE_INT *storage (), return a pointer to writable
      HOST_WIDE_INT storage of size len ().  This method is optional.
    - void set_len (unsigned l), adjust the size of the storage
      to at least l HWI words.

   Conversions of wide_int _to_ tree or RTX or HWI are explicit.

   Conversions to wide_int happen with overloads to the global
   function template wi () or via wide_int_traits specializations.  */

/* ???  With mixed length operations there are encoding issues
   for signed vs. unsigned numbers.  The easiest encoding is to
   say wide-ints are always signed which means that -1U needs
   the MSB of the wide-int storage as zero which means an extra
   word with zeros.  The sign-bit of a wide-int is then always
   storage()[len() & (1 << (HOST_BITS_PER_WIDE_INT - 1))].  */

template <class S>
class wide_int : private S
{
  /* Allow access to the storage object of operands.  */
  template <class S2>
  friend class wide_int;

public:
  typedef wide_int<S> WideInt_t;

  void construct (const S& s) { static_cast<S&>(*this) = s; }

  /* ???  We'd really want the following member templates to
     behave as a set of overloads available for each wide-int
     storage model.  Like
     WideInt_t& operator (const wide_int <wi_tree_int_cst>&);
     WideInt_t& operator (const wide_int <wi_embed>&);
     WideInt_t& operator (const wide_int <wi_embed_var>&);
     forwarding to a common implementation.  But that's not
     extensible from the outside (tree bits should reside
     in tree.h), nor is it possible without explicitely writing
     down all overloads and explicitely forwarding to the common
     implementation.  Thus we require the user to explicitely
     convert to wide-int via a function overload (see below).  */
  template <class S2>
  WideInt_t& operator=(const wide_int <S2>&);

  /* Self-modify operators have obvious result types.  */
  template <class T>
  WideInt_t& operator+=(const T&);

  /* Note the result must support an lvalue storage.  */
  /* Automatic promotion is difficult but could be done via another
     traits class wi_promote_lvalue<S1, S2>::S - of course then
     storage models would need to know about each others.  */
  // otoh it would lead to sub-optimal code anyway so we should
  // make the result available as reference parameter and only support
  // wide_int <> res; add (res, x, 1); ?
  template <class S1, class T>
  wide_int<S1> operator+(const T&);

  template <class T1, class T2>
  static wide_int<S>&
  add (wide_int<S>& res, const T1 &, const T2 &);

  HOST_WIDE_INT
  to_hwi () const { return this->storage()[0]; }
};


/* This traits class is to provide a means of accessing T as
   an rvalue wide-int.  This allows us to omit the explicit
   conversion to wide_int <storage> in most places and allow
   extending the wide-int interface outside of wide-int.h.

   Extend this by providing a constructor that builds a wrapper
   around type T and operator-> that provides access to a
   wide_int<> representing it.  */

template <class T>
class wi_traits;

/* Wrap a wide_int as itself.  */

template <class S>
class wi_traits <wide_int <S> >
{
public:
    typedef wide_int <S> wi_t;
    wi_traits(const wide_int <S> &w_) : w (w_) {}
    const wi_t* operator->() const { return &w; }
private:
    const wi_t &w;
};

/* Wrap any integral type up to the size of a (unsigned) HWI
   as wide_int <wi_embed <1> >.
   ???  The following only handles 'int', handling the rest
   of the suitable integer types via a separate helper trait is
   left as an excercise for the reader.  */

template <>
class wi_traits <int>
{
public:
    typedef wide_int <wi_embed <1> > wi_t;
    wi_traits(HOST_WIDE_INT hwi)
  {
    wi_embed <1> ws;
    ws.construct ();
    ws.storage()[0] = hwi;
    w.construct (ws);
  }
    wi_t* operator->() { return &w; }
private:
    wi_t w;
};


/* wide-int operations.  To avoid code-bloat the actual workers
   can be trivially outlined by giving them a non-template interface
   working on HOST_WIDE_INT * arrays.  */

template <class S>
template <class S2>
wide_int<S>&
wide_int<S>::operator=(const wide_int<S2>&b)
{
  unsigned i;
  this->set_len (b.len());
  for (i = 0; i < b.len(); ++i)
    this->storage()[i] = b.storage()[i];
  for (; i < this->len(); ++i)
    this->storage()[i] = 0;
  return *this;
}

template <class S>
template <class T>
wide_int<S>&
wide_int<S>::operator+=(const T &b_)
{
  wi_traits<T> b(b_);
  /* Compute a += b.  */
  unsigned i;
  if (b->len () > this->len ())
    this->set_len (b->len ());
  for (i = 0; i < this->len (); ++i)
    this->storage()[i] += b->storage()[i];
  return *this;
}

template <class S>
template <class S1, class T>
wide_int<S1>
wide_int<S>::operator+(const T &w)
{
  /* Compute a + b */
  wide_int<S1> res;
  // ???  Initialization from *this not possible via implicit
  // use of operator=  */
  // wide_int<S1> res = *this;
  res = *this;
  res += w;
  return res;
}

template <class S>
template <class T1, class T2>
wide_int<S>&
wide_int<S>::add(wide_int<S>& res, const T1&a_, const T2&b_)
{
  wi_traits<T1> a(a_);
  wi_traits<T2> b(b_);
  res.set_len (a->len () > b->len () ? a->len() : b->len ());
  for (unsigned i = 0; i < res.len (); ++i)
    res.storage()[i] = a->storage()[i] + b->storage()[i];
  return res;
}

// ----- for tree.h

class wi_tree_int_cst
{
  tree cst;
public:
  void construct (tree c) { cst = c; }
  const HOST_WIDE_INT *storage() const { return reinterpret_cast <HOST_WIDE_INT *>(&TREE_INT_CST (cst)); }
  unsigned len() const { return 2; }
};

template <>
class wi_traits <tree>
{
public:
    typedef wide_int <wi_tree_int_cst> wi_t;
    wi_traits(tree t)
  {
    wi_tree_int_cst ws;
    ws.construct (t);
    w.construct (ws);
  }
    wi_t* operator->() { return &w; }
private:
    wi_t w;
};


union T {
  wide_int<> w;
  unsigned x;
} test;

wide_int<wi_tree_int_cst> wi (tree t)
{
  wide_int<wi_tree_int_cst> w;
  wi_tree_int_cst ws;
  ws.construct (t);
  w.construct (ws);
  return w;
}
wide_int<wi_embed <1> > wi (HOST_WIDE_INT hwi)
{
  wide_int<wi_embed <1> > w;
  wi_embed <1> ws;
  ws.construct ();
  ws.storage()[0] = hwi;
  w.construct (ws);
  return w;
}

HOST_WIDE_INT
wi_test (tree x)
{
  // template argument deduction doesn't do the magic we want it to do
  // to make this kind of implicit conversions work
  // overload resolution considers this kind of conversions so we
  // need some magic that combines both ... but seeding the overload
  // set with some instantiations doesn't seem to be possible :/
  // wide_int<> w = x + 1;
  wide_int<> w;
  w += x;
  w += 1;
  // template argument deduction doesn't deduce the return value type,
  // not considering the template default argument either ...
  // w = wi (x) + 1;
  // we could support this by providing rvalue-to-lvalue promotion
  // via a traits class?
  // otoh it would lead to sub-optimal code anyway so we should
  // make the result available as reference parameter and only support
  // wide_int <> res; add (res, x, 1); ?
  w = wi (x).operator+<wide_int<> >(1);
  wide_int<>::add(w, x, 1);
  return w.to_hwi ();
}

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-02 15:40                                                                           ` Richard Biener
@ 2013-04-02 19:23                                                                             ` Kenneth Zadeck
  2013-04-03 10:44                                                                               ` Richard Biener
  2013-04-05 15:05                                                                             ` Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-02 19:23 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

Yes, I agree that you win the challenge that it can be done.    What you 
have always failed to address is why anyone would want to do this.  Or 
how this would at all be desirable.    But I completely agree that from 
a purely abstract point of view you can add a storage model.

Now here is why we REALLY do not want to go down this road:

1)  The following comment from your earlier mail is completely wrong

> +#ifdef NEW_REP_FOR_INT_CST
> +  /* This is the code once the tree level is converted.  */
> +  wide_int result;
> +  int i;
> +
> +  tree type = TREE_TYPE (tcst);
> +
> +  result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
> +  result.precision = TYPE_PRECISION (type);
> +  result.len = TREE_INT_CST_LEN (tcst);
> +  for (i = 0; i < result.len; i++)
> +    result.val[i] = TREE_INT_CST_ELT (tcst, i);
> +
> +  return result;
> +#else

> this also shows the main reason I was asking for storage abstraction.
> The initialization from tree is way too expensive.

In almost all cases, constants will fit in a single HWI.  Thus, the only 
thing that you are copying is the length and a single HWI. So you are 
dragging in a lot of machinery just to save these two copies?   
Certainly there has to be more to it than that.

2)  You present this as if the implementor actually should care about 
the implementation and you give 3 alternatives:  the double_int, the 
current one, and HWI.     We have tried to make it so that the client 
should not care.   Certainly in my experience here, I have not found a 
place to care.

In my opinion double_int needs to go away.  That is the main thrust of 
my patches.   There is no place in a compiler for an abi that depends on 
constants fitting into 2 two words whose size is defined by the host.    
This is not a beauty contest argument, we have public ports are 
beginning to use modes that are larger than two x86-64 HWIs and i have a 
private port that has such modes and it is my experience that any pass 
that uses this interface has one of three behaviors: it silently gets 
the wrong answer, it ices, or it fails to do the transformation.  If we 
leave double_int as an available option, then any use of it potentially 
will have one of these three behaviors.  And so one of my strong 
objections to this direction is that i do not want to fight this kind of 
bug for the rest of my life.    Having a single storage model that just 
always works is in my opinion a highly desirable option.  What you have 
never answered in a concrete manner is, if we decide to provide this 
generality, what it would be used for.    There is no place in a 
portable compiler where the right answer for every target is two HOST 
wide integers.

However, i will admit that the HWI option has some merits.   We try to 
address this in our implementation by dividing what is done inline in 
wide-int.h to the cases that fit in an HWI and then only drop into the 
heavy code in wide-int.c if mode is larger (which it rarely will be).   
However, a case could be made that for certain kinds of things like 
string lengths and such, we could use another interface or as you argue, 
a different storage model with the same interface.   I just do not see 
that the cost of the conversion code is really going to show up on 
anyone's radar.

3) your trick will work at the tree level, but not at the rtl level.   
The wide-int code cannot share storage with the CONST_INTs.    We tried 
this, and there are a million bugs that would have to be fixed to make 
it work.    It could have worked if CONST_INTs had carried a mode 
around, but since they do not, you end up with the same CONST_INT 
sharing the rep for several different types and that just did not work 
unless you are willing to do substantial cleanups.

On 04/02/2013 11:04 AM, Richard Biener wrote:
> On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> This patch contains a large number of the changes requested by Richi.   It
>> does not contain any of the changes that he requested to abstract the
>> storage layer.   That suggestion appears to be quite unworkable.
> I of course took this claim as a challenge ... with the following result.  It is
> of course quite workable ;)
>
> The attached patch implements the core wide-int class and three storage
> models (fixed size for things like plain HWI and double-int, variable size
> similar to how your wide-int works and an adaptor for the double-int as
> contained in trees).  With that you can now do
>
> HOST_WIDE_INT
> wi_test (tree x)
> {
>    // template argument deduction doesn't do the magic we want it to do
>    // to make this kind of implicit conversions work
>    // overload resolution considers this kind of conversions so we
>    // need some magic that combines both ... but seeding the overload
>    // set with some instantiations doesn't seem to be possible :/
>    // wide_int<> w = x + 1;
>    wide_int<> w;
>    w += x;
>    w += 1;
>    // template argument deduction doesn't deduce the return value type,
>    // not considering the template default argument either ...
>    // w = wi (x) + 1;
>    // we could support this by providing rvalue-to-lvalue promotion
>    // via a traits class?
>    // otoh it would lead to sub-optimal code anyway so we should
>    // make the result available as reference parameter and only support
>    // wide_int <> res; add (res, x, 1); ?
>    w = wi (x).operator+<wide_int<> >(1);
>    wide_int<>::add(w, x, 1);
>    return w.to_hwi ();
> }
>
> we are somewhat limited with C++ unless we want to get really fancy.
> Eventually providing operator+ just doesn't make much sense for
> generic wide-int combinations (though then the issue is its operands
> are no longer commutative which I think is the case with your wide-int
> or double-int as well - they don't suport "1 + wide_int" for obvious reasons).
>
> So there are implementation design choices left undecided.
>
> Oh, and the operation implementations are crap (they compute nonsense).
>
> But you should get the idea.
>
> Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch - patch ping for the next stage 1
  2013-04-02 15:29                                             ` Richard Biener
@ 2013-04-02 22:43                                               ` Kenneth Zadeck
  2013-04-03 10:48                                                 ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-02 22:43 UTC (permalink / raw)
  To: Richard Biener
  Cc: Joseph S. Myers, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 4978 bytes --]

this time for sure.

kenny
On 04/02/2013 10:54 AM, Richard Biener wrote:
> On Tue, Apr 2, 2013 at 3:49 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> Richard,
>>
>> did everything that you asked here.  bootstrapped and regtested on x86-64.
>> ok to commit?
> diff --git a/gcc/hwint.c b/gcc/hwint.c
> index 330b42c..7e5b85c 100644
> --- a/gcc/hwint.c
> +++ b/gcc/hwint.c
> @@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b)
>   {
>     return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b));
>   }
> +
> +#ifndef ENABLE_CHECKING
> +/* Sign extend SRC starting from PREC.  */
> +
> +HOST_WIDE_INT
> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>
> this should go to hwint.h, and without the masking of prec.
> while ...
>
> diff --git a/gcc/hwint.h b/gcc/hwint.h
> index da62fad..9dddf05 100644
> --- a/gcc/hwint.h
> +++ b/gcc/hwint.h
> @@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT,
> HOST_WIDE_INT);
>   extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
>   extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT);
>
> +/* Sign extend SRC starting from PREC.  */
> +
> +#ifdef ENABLE_CHECKING
> +extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
> +#else
> +static inline HOST_WIDE_INT
> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
> +{
> +  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
>
> this should go to hwint.c (also without masking prec).
>
> Richard.
>
>
>
>
>> kenny
>>
>>
>> On 04/02/2013 05:38 AM, Richard Biener wrote:
>>> On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck
>>> <zadeck@naturalbridge.com> wrote:
>>>> richard,
>>>>
>>>> I was able to add everything except for the checking asserts.    While I
>>>> think that this is a reasonable idea, it is difficult to add that to a
>>>> function that is defined in hwint.h because of circular includes.   I
>>>> could
>>>> move this another file (though this appears to be the logical correct
>>>> place
>>>> for it), or we can do without the asserts.
>>>>
>>>> The context is that [sz]ext_hwi is that are used are over the compiler
>>>> but
>>>> are generally written out long.   The wide-int class uses them also, but
>>>> wide-int did not see like the right place for them to live and i believe
>>>> that you suggested that i move them.
>>>>
>>>> ok to commit, or do you have a suggested resolution to the assert issue?
>>> Yes, do
>>>
>>> #ifdef ENABLE_CHECKING
>>> extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
>>> #else
>>> +/* Sign extend SRC starting from PREC.  */
>>> +
>>> +static inline HOST_WIDE_INT
>>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>> +{
>>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>>> +    return src;
>>> +  else
>>> +    {
>>>           int shift = HOST_BITS_PER_WIDE_INT - prec;
>>> +      return (src << shift) >> shift;
>>> +    }
>>> +}
>>> #endif
>>>
>>> and for ENABLE_CHECKING only provide an out-of-line implementation
>>> in hwint.c.  That's how we did it with abs_hwi (well, we just do not
>>> provide
>>> an inline variant there - that's another possibility).
>>>
>>> Note that hwint.h is always included after config.h so the ENABLE_CHECKING
>>> definition should be available.
>>>
>>> Richard.
>>>
>>>> kenny
>>>>
>>>>
>>>> On 03/27/2013 10:13 AM, Richard Biener wrote:
>>>>> On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck
>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>> Here is the first of my wide int patches with joseph's comments and the
>>>>>> patch rot removed.
>>>>>>
>>>>>> I would like to get these pre approved for the next stage 1.
>>>>> +      int shift = HOST_BITS_PER_WIDE_INT - (prec &
>>>>> (HOST_BITS_PER_WIDE_INT - 1));
>>>>>
>>>>> I think this should gcc_checking_assert that prec is not out of range
>>>>> (any reason why prec is signed int and not unsigned int?) rather than
>>>>> ignore bits in prec.
>>>>>
>>>>> +static inline HOST_WIDE_INT
>>>>> +zext_hwi (HOST_WIDE_INT src, int prec)
>>>>> +{
>>>>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>>>>> +    return src;
>>>>> +  else
>>>>> +    return src & (((HOST_WIDE_INT)1
>>>>> +                  << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
>>>>> +}
>>>>>
>>>>> likewise.  Also I'm not sure I agree about the signedness of the result
>>>>> /
>>>>> src.
>>>>> zext_hwi (-1, HOST_BITS_PER_WIDE_INT) < 0 is true which is odd.
>>>>>
>>>>> The patch misses context of uses, so I'm not sure what the above
>>>>> functions
>>>>> are intended to do.
>>>>>
>>>>> Richard.
>>>>>
>>>>>> On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
>>>>>>> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>>>>>>>
>>>>>>>> +# define HOST_HALF_WIDE_INT_PRINT "h"
>>>>>>> This may cause problems on hosts not supporting %hd (MinGW?), and
>>>>>>> there's
>>>>>>> no real need for using "h" here given the promotion of short to int;
>>>>>>> you
>>>>>>> can just use "" (rather than e.g. needing special handling in
>>>>>>> xm-mingw32.h
>>>>>>> like is done for HOST_LONG_LONG_FORMAT).
>>>>>>>


[-- Attachment #2: p1-6.diff --]
[-- Type: text/x-patch, Size: 5173 bytes --]

diff --git a/gcc/hwint.c b/gcc/hwint.c
index 330b42c..92d54a3 100644
--- a/gcc/hwint.c
+++ b/gcc/hwint.c
@@ -204,3 +204,35 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b)
 {
   return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b));
 }
+
+#ifndef ENABLE_CHECKING
+/* Sign extend SRC starting from PREC.  */
+
+HOST_WIDE_INT
+sext_hwi (HOST_WIDE_INT src, unsigned int prec)
+{
+  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
+
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    {
+      int shift = HOST_BITS_PER_WIDE_INT - prec;
+      return (src << shift) >> shift;
+    }
+}
+
+/* Zero extend SRC starting from PREC.  */
+
+unsigned HOST_WIDE_INT
+zext_hwi (unsigned HOST_WIDE_INT src, unsigned int prec)
+{
+  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
+
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    return src & (((HOST_WIDE_INT)1 << prec) - 1);
+}
+
+#endif
diff --git a/gcc/hwint.h b/gcc/hwint.h
index da62fad..dbf0239 100644
--- a/gcc/hwint.h
+++ b/gcc/hwint.h
@@ -76,6 +76,40 @@ extern char sizeof_long_long_must_be_8[sizeof(long long) == 8 ? 1 : -1];
 # endif
 #endif
 
+/* Print support for half a host wide int.  */
+#define HOST_BITS_PER_HALF_WIDE_INT (HOST_BITS_PER_WIDE_INT / 2)
+#if HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_LONG
+# define HOST_HALF_WIDE_INT long
+# define HOST_HALF_WIDE_INT_PRINT HOST_LONG_FORMAT
+# define HOST_HALF_WIDE_INT_PRINT_C "L"
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_INT
+# define HOST_HALF_WIDE_INT int
+# define HOST_HALF_WIDE_INT_PRINT ""
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#elif HOST_BITS_PER_HALF_WIDE_INT == HOST_BITS_PER_SHORT
+# define HOST_HALF_WIDE_INT short
+# define HOST_HALF_WIDE_INT_PRINT ""
+# define HOST_HALF_WIDE_INT_PRINT_C ""
+# define HOST_HALF_WIDE_INT_PRINT_DEC "%" HOST_HALF_WIDE_INT_PRINT "d"
+# define HOST_HALF_WIDE_INT_PRINT_DEC_C HOST_HALF_WIDE_INT_PRINT_DEC HOST_HALF_WIDE_INT_PRINT_C
+# define HOST_HALF_WIDE_INT_PRINT_UNSIGNED "%" HOST_HALF_WIDE_INT_PRINT "u"
+# define HOST_HALF_WIDE_INT_PRINT_HEX "%#" HOST_HALF_WIDE_INT_PRINT "x"
+# define HOST_HALF_WIDE_INT_PRINT_HEX_PURE "%" HOST_HALF_WIDE_INT_PRINT "x"
+#else
+#error Please add support for HOST_HALF_WIDE_INT
+#endif
+
+
 #define HOST_WIDE_INT_1 HOST_WIDE_INT_C(1)
 
 /* This is a magic identifier which allows GCC to figure out the type
@@ -93,9 +127,13 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
 # if HOST_BITS_PER_WIDE_INT == 64
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%016" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%016" HOST_LONG_FORMAT "x"
 # else
 #  define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
      "0x%" HOST_LONG_FORMAT "x%08" HOST_LONG_FORMAT "x"
+#  define HOST_WIDE_INT_PRINT_PADDED_HEX \
+     "%08" HOST_LONG_FORMAT "x"
 # endif
 #else
 # define HOST_WIDE_INT_PRINT HOST_LONG_LONG_FORMAT
@@ -103,6 +141,8 @@ typedef HOST_WIDE_INT __gcc_host_wide_int__;
   /* We can assume that 'long long' is at least 64 bits.  */
 # define HOST_WIDE_INT_PRINT_DOUBLE_HEX \
     "0x%" HOST_LONG_LONG_FORMAT "x%016" HOST_LONG_LONG_FORMAT "x"
+# define HOST_WIDE_INT_PRINT_PADDED_HEX \
+    "%016" HOST_LONG_LONG_FORMAT "x"
 #endif /* HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG */
 
 #define HOST_WIDE_INT_PRINT_DEC "%" HOST_WIDE_INT_PRINT "d"
@@ -276,4 +316,36 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT, HOST_WIDE_INT);
 
+/* Sign extend SRC starting from PREC.  */
+
+#ifdef ENABLE_CHECKING
+extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
+#else
+static inline HOST_WIDE_INT
+sext_hwi (HOST_WIDE_INT src, unsigned int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    {
+      int shift = HOST_BITS_PER_WIDE_INT - prec;
+      return (src << shift) >> shift;
+    }
+}
+#endif
+
+/* Zero extend SRC starting from PREC.  */
+#ifdef ENABLE_CHECKING
+extern unsigned HOST_WIDE_INT zext_hwi (unsigned HOST_WIDE_INT, unsigned int);
+#else
+static inline unsigned HOST_WIDE_INT
+zext_hwi (unsigned HOST_WIDE_INT src, unsigned int prec)
+{
+  if (prec == HOST_BITS_PER_WIDE_INT)
+    return src;
+  else
+    return src & (((HOST_WIDE_INT)1 << prec) - 1);
+}
+#endif
+
 #endif /* ! GCC_HWINT_H */

[-- Attachment #3: p1-5.clog --]
[-- Type: text/plain, Size: 437 bytes --]

2013-4-02  Kenneth Zadeck <zadeck@naturalbridge.com>

	* hwint.c (sext_hwi, zext_hwi): New functions.
	* hwint.h (HOST_BITS_PER_HALF_WIDE_INT, HOST_HALF_WIDE_INT,
	HOST_HALF_WIDE_INT_PRINT, HOST_HALF_WIDE_INT_PRINT_C,
	HOST_HALF_WIDE_INT_PRINT_DEC, HOST_HALF_WIDE_INT_PRINT_DEC_C,
	HOST_HALF_WIDE_INT_PRINT_UNSIGNED, HOST_HALF_WIDE_INT_PRINT_HEX,
	HOST_HALF_WIDE_INT_PRINT_HEX_PURE): New symbols.
	(sext_hwi, zext_hwi): New functions.
	

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-02 19:23                                                                             ` Kenneth Zadeck
@ 2013-04-03 10:44                                                                               ` Richard Biener
  2013-04-03 13:36                                                                                 ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-03 10:44 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On Tue, Apr 2, 2013 at 7:35 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> Yes, I agree that you win the challenge that it can be done.    What you
> have always failed to address is why anyone would want to do this.  Or how
> this would at all be desirable.    But I completely agree that from a purely
> abstract point of view you can add a storage model.
>
> Now here is why we REALLY do not want to go down this road:
>
> 1)  The following comment from your earlier mail is completely wrong
>
>
>> +#ifdef NEW_REP_FOR_INT_CST
>> +  /* This is the code once the tree level is converted.  */
>> +  wide_int result;
>> +  int i;
>> +
>> +  tree type = TREE_TYPE (tcst);
>> +
>> +  result.bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
>> +  result.precision = TYPE_PRECISION (type);
>> +  result.len = TREE_INT_CST_LEN (tcst);
>> +  for (i = 0; i < result.len; i++)
>> +    result.val[i] = TREE_INT_CST_ELT (tcst, i);
>> +
>> +  return result;
>> +#else
>
>
>> this also shows the main reason I was asking for storage abstraction.
>> The initialization from tree is way too expensive.
>
>
> In almost all cases, constants will fit in a single HWI.  Thus, the only
> thing that you are copying is the length and a single HWI. So you are
> dragging in a lot of machinery just to save these two copies?   Certainly
> there has to be more to it than that.

In the end you will have a variable-size storage in TREE_INT_CST thus
you will have at least to emit _code_ copying over meta-data and data
from the tree representation to the wide-int (similar for RTX CONST_DOUBLE/INT).
I'm objecting to the amount of code you emit and agree that the runtime
cost is copying the meta-data (hopefully optimizable via CSE / SRA)
and in most cases one (or two) iterations of the loop copying the data
(not optimizable).

> 2)  You present this as if the implementor actually should care about the
> implementation and you give 3 alternatives:  the double_int, the current
> one, and HWI.     We have tried to make it so that the client should not
> care.   Certainly in my experience here, I have not found a place to care.

Well, similar as for the copying overhead for tree your approach requires
overloading operations for HOST_WIDE_INT operands to be able to
say wi + 1 (which is certainly desirable), or the overhead of using
wide_int_one ().

> In my opinion double_int needs to go away.  That is the main thrust of my
> patches.   There is no place in a compiler for an abi that depends on
> constants fitting into 2 two words whose size is defined by the host.

That's true.  I'm not arguing to preserve "double-int" - I'm arguing to
preserve a way to ask for an integer type on the host with (at least)
N bits.  Almost all double-int users really ask for an integer type on the
host that has at least as many bits as the pointer representation (or
word_mode) on
the target (we do have HOST_WIDEST_INT == 32bits for 64bit pointer
targets).  No double-int user specifically wants 2 * HOST_WIDE_INT
precision - that is just what happens to be there.  Thus I am providing
a way to say get me a host integer with at least N bits (VRP asks for
this, for example).

What I was asking for is that whatever can provide the above should share
the functional interface with wide-int (or the othert way around).  And I
was claiming that wide-int is too fat, because current users of double-int
eventually store double-ints permanently.

> This is not a beauty contest argument, we have public ports are beginning to
> use modes that are larger than two x86-64 HWIs and i have a private port
> that has such modes and it is my experience that any pass that uses this
> interface has one of three behaviors: it silently gets the wrong answer, it
> ices, or it fails to do the transformation.  If we leave double_int as an
> available option, then any use of it potentially will have one of these
> three behaviors.  And so one of my strong objections to this direction is
> that i do not want to fight this kind of bug for the rest of my life.
> Having a single storage model that just always works is in my opinion a
> highly desirable option.  What you have never answered in a concrete manner
> is, if we decide to provide this generality, what it would be used for.
> There is no place in a portable compiler where the right answer for every
> target is two HOST wide integers.
>
> However, i will admit that the HWI option has some merits.   We try to
> address this in our implementation by dividing what is done inline in
> wide-int.h to the cases that fit in an HWI and then only drop into the heavy
> code in wide-int.c if mode is larger (which it rarely will be).   However, a
> case could be made that for certain kinds of things like string lengths and
> such, we could use another interface or as you argue, a different storage
> model with the same interface.   I just do not see that the cost of the
> conversion code is really going to show up on anyone's radar.

What's the issue with abstracting away the model so a fixed-size 'len'
is possible?  (let away the argument that this would easily allow an
adaptor to tree)

> 3) your trick will work at the tree level, but not at the rtl level.   The
> wide-int code cannot share storage with the CONST_INTs.    We tried this,
> and there are a million bugs that would have to be fixed to make it work.
> It could have worked if CONST_INTs had carried a mode around, but since they
> do not, you end up with the same CONST_INT sharing the rep for several
> different types and that just did not work unless you are willing to do
> substantial cleanups.

I don't believe you.  I am only asking for the adaptors to tree and RTL to
work in an RVALUE-ish way (no modification, as obviously RTL and tree
constants may be shared).  I think your claim is because you have that
precision and bitsize members in your wide-int which I believe is a
design red herring.  I suppose we should concentrate on addressing that
one first.  Thus, let me repeat a few questions on your design to eventually
let you understand my concerns:

Given two wide-ints, a and b, what precision will the result of
     a + b
have?  Consider a having precision 32 and b having precision 64
on a 32-bit HWI host.

You define wide-int to have no sign information:

+   The representation does not contain any information about
+   signedness of the represented value, so it can be used to represent
+   both signed and unsigned numbers.  For operations where the results
+   depend on signedness (division, comparisons), the signedness must
+   be specified separately.  For operations where the signness
+   matters, one of the operands to the operation specifies either
+   wide_int::SIGNED or wide_int::UNSIGNED.

but the result of operations on mixed precision operands _does_ depend
on the sign, nevertheless most operations do not get a signedness argument.
Nor would that help, because it depends on the signedness of the individual
operands!

double-int get's around this by having a common "precision" to which
all smaller precision constants have to be sign-/zero-extended.  So
does CONST_INT and CONST_DOUBLE.

Note that even with same precision you have introduced the same problem
with the variable len.

My proposal is simple - all wide-ints are signed!  wide-int is basically
an arbitrary precision signed integer format.  The sign is encoded in
the most significant bit of the last active HWI of the representation
(val[len - 1] & (1 << HOST_BITS_PER_WIDE_INT - 1)).  All values
with less precision than len * HOST_BITS_PER_WIDE_INT are
properly sign-/zero-extended to precision len * HOST_BITS_PER_WIDE_INT.

This let's you define mixed len operations by implicitely sign-/zero-extending
the operands to whatever len is required for the operation.

Furthermore it allows you to get rid of the precision member (and
bitsize anyway).
Conversion from tree / RTL requires information on the signedness of the
input (trivial for tree, for RTL all constants are signed - well,
sign-extended).
Whenever you want to transfer the wide-int to tree / RTL you have to
sign-/zero-extend according to the desired precision.  If you need sth else
than arbitrary precision arithmetic you have to explicitely truncate / extend
at suitable places - with overflow checking being trivial here.  For
optimization
purposes selected operations may benefit from a combined implementation
receiving a target precision and signedness.  Whatever extra meta-data
RTL requires does not belong in wide-int but in the RTX.  Trivially
a mode comes to my mind (on tree we have a type), and trivially
each RTX has a mode.  And each mode has a precision and bitsize.
It lacks a sign, so all RTL integer constants are sign-extended for
encoding efficiency purposes.  mixed-mode operations will not
occur (mixed len operations will), mixed-mode ops are exclusively
sign-/zero-extensions and truncations.

Representation of (unsigned HOST_WIDE_INT)-1 would necessarily
be { 0, (unsigned HOST_WIDE_INT)-1 }, representation of -1 in any
precision would be { -1 }.

That was my proposal.  Now, can you please properly specify yours?

Thanks,
Richard.

>
> On 04/02/2013 11:04 AM, Richard Biener wrote:
>>
>> On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck
>> <zadeck@naturalbridge.com> wrote:
>>>
>>> This patch contains a large number of the changes requested by Richi.
>>> It
>>> does not contain any of the changes that he requested to abstract the
>>> storage layer.   That suggestion appears to be quite unworkable.
>>
>> I of course took this claim as a challenge ... with the following result.
>> It is
>> of course quite workable ;)
>>
>> The attached patch implements the core wide-int class and three storage
>> models (fixed size for things like plain HWI and double-int, variable size
>> similar to how your wide-int works and an adaptor for the double-int as
>> contained in trees).  With that you can now do
>>
>> HOST_WIDE_INT
>> wi_test (tree x)
>> {
>>    // template argument deduction doesn't do the magic we want it to do
>>    // to make this kind of implicit conversions work
>>    // overload resolution considers this kind of conversions so we
>>    // need some magic that combines both ... but seeding the overload
>>    // set with some instantiations doesn't seem to be possible :/
>>    // wide_int<> w = x + 1;
>>    wide_int<> w;
>>    w += x;
>>    w += 1;
>>    // template argument deduction doesn't deduce the return value type,
>>    // not considering the template default argument either ...
>>    // w = wi (x) + 1;
>>    // we could support this by providing rvalue-to-lvalue promotion
>>    // via a traits class?
>>    // otoh it would lead to sub-optimal code anyway so we should
>>    // make the result available as reference parameter and only support
>>    // wide_int <> res; add (res, x, 1); ?
>>    w = wi (x).operator+<wide_int<> >(1);
>>    wide_int<>::add(w, x, 1);
>>    return w.to_hwi ();
>> }
>>
>> we are somewhat limited with C++ unless we want to get really fancy.
>> Eventually providing operator+ just doesn't make much sense for
>> generic wide-int combinations (though then the issue is its operands
>> are no longer commutative which I think is the case with your wide-int
>> or double-int as well - they don't suport "1 + wide_int" for obvious
>> reasons).
>>
>> So there are implementation design choices left undecided.
>>
>> Oh, and the operation implementations are crap (they compute nonsense).
>>
>> But you should get the idea.
>>
>> Richard.
>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch - patch ping for the next stage 1
  2013-04-02 22:43                                               ` Kenneth Zadeck
@ 2013-04-03 10:48                                                 ` Richard Biener
  2013-04-03 12:21                                                   ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-03 10:48 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Joseph S. Myers, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

On Tue, Apr 2, 2013 at 9:08 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> this time for sure.

Almost ...

diff --git a/gcc/hwint.c b/gcc/hwint.c
index 330b42c..92d54a3 100644
--- a/gcc/hwint.c
+++ b/gcc/hwint.c
@@ -204,3 +204,35 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b)
 {
   return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b));
 }
+
+#ifndef ENABLE_CHECKING

#ifdef ENABLE_CHECKING

+/* Sign extend SRC starting from PREC.  */
+
+HOST_WIDE_INT
+sext_hwi (HOST_WIDE_INT src, unsigned int prec)
+{
+  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
+

Ok with that change.  (maybe catch one random use of the pattern
in code and use the helpers - that would have catched this issue)

Thanks,
Richard.



> kenny
>
> On 04/02/2013 10:54 AM, Richard Biener wrote:
>>
>> On Tue, Apr 2, 2013 at 3:49 PM, Kenneth Zadeck <zadeck@naturalbridge.com>
>> wrote:
>>>
>>> Richard,
>>>
>>> did everything that you asked here.  bootstrapped and regtested on
>>> x86-64.
>>> ok to commit?
>>
>> diff --git a/gcc/hwint.c b/gcc/hwint.c
>> index 330b42c..7e5b85c 100644
>> --- a/gcc/hwint.c
>> +++ b/gcc/hwint.c
>> @@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT
>> b)
>>   {
>>     return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b));
>>   }
>> +
>> +#ifndef ENABLE_CHECKING
>> +/* Sign extend SRC starting from PREC.  */
>> +
>> +HOST_WIDE_INT
>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>
>> this should go to hwint.h, and without the masking of prec.
>> while ...
>>
>> diff --git a/gcc/hwint.h b/gcc/hwint.h
>> index da62fad..9dddf05 100644
>> --- a/gcc/hwint.h
>> +++ b/gcc/hwint.h
>> @@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT,
>> HOST_WIDE_INT);
>>   extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
>>   extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT,
>> HOST_WIDE_INT);
>>
>> +/* Sign extend SRC starting from PREC.  */
>> +
>> +#ifdef ENABLE_CHECKING
>> +extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
>> +#else
>> +static inline HOST_WIDE_INT
>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>> +{
>> +  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
>>
>> this should go to hwint.c (also without masking prec).
>>
>> Richard.
>>
>>
>>
>>
>>> kenny
>>>
>>>
>>> On 04/02/2013 05:38 AM, Richard Biener wrote:
>>>>
>>>> On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck
>>>> <zadeck@naturalbridge.com> wrote:
>>>>>
>>>>> richard,
>>>>>
>>>>> I was able to add everything except for the checking asserts.    While
>>>>> I
>>>>> think that this is a reasonable idea, it is difficult to add that to a
>>>>> function that is defined in hwint.h because of circular includes.   I
>>>>> could
>>>>> move this another file (though this appears to be the logical correct
>>>>> place
>>>>> for it), or we can do without the asserts.
>>>>>
>>>>> The context is that [sz]ext_hwi is that are used are over the compiler
>>>>> but
>>>>> are generally written out long.   The wide-int class uses them also,
>>>>> but
>>>>> wide-int did not see like the right place for them to live and i
>>>>> believe
>>>>> that you suggested that i move them.
>>>>>
>>>>> ok to commit, or do you have a suggested resolution to the assert
>>>>> issue?
>>>>
>>>> Yes, do
>>>>
>>>> #ifdef ENABLE_CHECKING
>>>> extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
>>>> #else
>>>> +/* Sign extend SRC starting from PREC.  */
>>>> +
>>>> +static inline HOST_WIDE_INT
>>>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>>> +{
>>>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>>>> +    return src;
>>>> +  else
>>>> +    {
>>>>           int shift = HOST_BITS_PER_WIDE_INT - prec;
>>>> +      return (src << shift) >> shift;
>>>> +    }
>>>> +}
>>>> #endif
>>>>
>>>> and for ENABLE_CHECKING only provide an out-of-line implementation
>>>> in hwint.c.  That's how we did it with abs_hwi (well, we just do not
>>>> provide
>>>> an inline variant there - that's another possibility).
>>>>
>>>> Note that hwint.h is always included after config.h so the
>>>> ENABLE_CHECKING
>>>> definition should be available.
>>>>
>>>> Richard.
>>>>
>>>>> kenny
>>>>>
>>>>>
>>>>> On 03/27/2013 10:13 AM, Richard Biener wrote:
>>>>>>
>>>>>> On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck
>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>
>>>>>>> Here is the first of my wide int patches with joseph's comments and
>>>>>>> the
>>>>>>> patch rot removed.
>>>>>>>
>>>>>>> I would like to get these pre approved for the next stage 1.
>>>>>>
>>>>>> +      int shift = HOST_BITS_PER_WIDE_INT - (prec &
>>>>>> (HOST_BITS_PER_WIDE_INT - 1));
>>>>>>
>>>>>> I think this should gcc_checking_assert that prec is not out of range
>>>>>> (any reason why prec is signed int and not unsigned int?) rather than
>>>>>> ignore bits in prec.
>>>>>>
>>>>>> +static inline HOST_WIDE_INT
>>>>>> +zext_hwi (HOST_WIDE_INT src, int prec)
>>>>>> +{
>>>>>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>>>>>> +    return src;
>>>>>> +  else
>>>>>> +    return src & (((HOST_WIDE_INT)1
>>>>>> +                  << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
>>>>>> +}
>>>>>>
>>>>>> likewise.  Also I'm not sure I agree about the signedness of the
>>>>>> result
>>>>>> /
>>>>>> src.
>>>>>> zext_hwi (-1, HOST_BITS_PER_WIDE_INT) < 0 is true which is odd.
>>>>>>
>>>>>> The patch misses context of uses, so I'm not sure what the above
>>>>>> functions
>>>>>> are intended to do.
>>>>>>
>>>>>> Richard.
>>>>>>
>>>>>>> On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
>>>>>>>>
>>>>>>>> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>>>>>>>>
>>>>>>>>> +# define HOST_HALF_WIDE_INT_PRINT "h"
>>>>>>>>
>>>>>>>> This may cause problems on hosts not supporting %hd (MinGW?), and
>>>>>>>> there's
>>>>>>>> no real need for using "h" here given the promotion of short to int;
>>>>>>>> you
>>>>>>>> can just use "" (rather than e.g. needing special handling in
>>>>>>>> xm-mingw32.h
>>>>>>>> like is done for HOST_LONG_LONG_FORMAT).
>>>>>>>>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch - patch ping for the next stage 1
  2013-04-03 10:48                                                 ` Richard Biener
@ 2013-04-03 12:21                                                   ` Kenneth Zadeck
  2013-04-03 13:38                                                     ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-03 12:21 UTC (permalink / raw)
  To: Richard Biener
  Cc: Joseph S. Myers, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

yes, i had caught that when i merged it in with the patches that used 
it, is it ok aside from that?
kenny
On 04/03/2013 05:32 AM, Richard Biener wrote:
> On Tue, Apr 2, 2013 at 9:08 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> this time for sure.
> Almost ...
>
> diff --git a/gcc/hwint.c b/gcc/hwint.c
> index 330b42c..92d54a3 100644
> --- a/gcc/hwint.c
> +++ b/gcc/hwint.c
> @@ -204,3 +204,35 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT b)
>   {
>     return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b));
>   }
> +
> +#ifndef ENABLE_CHECKING
>
> #ifdef ENABLE_CHECKING
>
> +/* Sign extend SRC starting from PREC.  */
> +
> +HOST_WIDE_INT
> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
> +{
> +  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
> +
>
> Ok with that change.  (maybe catch one random use of the pattern
> in code and use the helpers - that would have catched this issue)
>
> Thanks,
> Richard.
>
>
>
>> kenny
>>
>> On 04/02/2013 10:54 AM, Richard Biener wrote:
>>> On Tue, Apr 2, 2013 at 3:49 PM, Kenneth Zadeck <zadeck@naturalbridge.com>
>>> wrote:
>>>> Richard,
>>>>
>>>> did everything that you asked here.  bootstrapped and regtested on
>>>> x86-64.
>>>> ok to commit?
>>> diff --git a/gcc/hwint.c b/gcc/hwint.c
>>> index 330b42c..7e5b85c 100644
>>> --- a/gcc/hwint.c
>>> +++ b/gcc/hwint.c
>>> @@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT
>>> b)
>>>    {
>>>      return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b));
>>>    }
>>> +
>>> +#ifndef ENABLE_CHECKING
>>> +/* Sign extend SRC starting from PREC.  */
>>> +
>>> +HOST_WIDE_INT
>>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>>
>>> this should go to hwint.h, and without the masking of prec.
>>> while ...
>>>
>>> diff --git a/gcc/hwint.h b/gcc/hwint.h
>>> index da62fad..9dddf05 100644
>>> --- a/gcc/hwint.h
>>> +++ b/gcc/hwint.h
>>> @@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT,
>>> HOST_WIDE_INT);
>>>    extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
>>>    extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT,
>>> HOST_WIDE_INT);
>>>
>>> +/* Sign extend SRC starting from PREC.  */
>>> +
>>> +#ifdef ENABLE_CHECKING
>>> +extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
>>> +#else
>>> +static inline HOST_WIDE_INT
>>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>> +{
>>> +  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
>>>
>>> this should go to hwint.c (also without masking prec).
>>>
>>> Richard.
>>>
>>>
>>>
>>>
>>>> kenny
>>>>
>>>>
>>>> On 04/02/2013 05:38 AM, Richard Biener wrote:
>>>>> On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck
>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>> richard,
>>>>>>
>>>>>> I was able to add everything except for the checking asserts.    While
>>>>>> I
>>>>>> think that this is a reasonable idea, it is difficult to add that to a
>>>>>> function that is defined in hwint.h because of circular includes.   I
>>>>>> could
>>>>>> move this another file (though this appears to be the logical correct
>>>>>> place
>>>>>> for it), or we can do without the asserts.
>>>>>>
>>>>>> The context is that [sz]ext_hwi is that are used are over the compiler
>>>>>> but
>>>>>> are generally written out long.   The wide-int class uses them also,
>>>>>> but
>>>>>> wide-int did not see like the right place for them to live and i
>>>>>> believe
>>>>>> that you suggested that i move them.
>>>>>>
>>>>>> ok to commit, or do you have a suggested resolution to the assert
>>>>>> issue?
>>>>> Yes, do
>>>>>
>>>>> #ifdef ENABLE_CHECKING
>>>>> extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
>>>>> #else
>>>>> +/* Sign extend SRC starting from PREC.  */
>>>>> +
>>>>> +static inline HOST_WIDE_INT
>>>>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>>>> +{
>>>>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>>>>> +    return src;
>>>>> +  else
>>>>> +    {
>>>>>            int shift = HOST_BITS_PER_WIDE_INT - prec;
>>>>> +      return (src << shift) >> shift;
>>>>> +    }
>>>>> +}
>>>>> #endif
>>>>>
>>>>> and for ENABLE_CHECKING only provide an out-of-line implementation
>>>>> in hwint.c.  That's how we did it with abs_hwi (well, we just do not
>>>>> provide
>>>>> an inline variant there - that's another possibility).
>>>>>
>>>>> Note that hwint.h is always included after config.h so the
>>>>> ENABLE_CHECKING
>>>>> definition should be available.
>>>>>
>>>>> Richard.
>>>>>
>>>>>> kenny
>>>>>>
>>>>>>
>>>>>> On 03/27/2013 10:13 AM, Richard Biener wrote:
>>>>>>> On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck
>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>> Here is the first of my wide int patches with joseph's comments and
>>>>>>>> the
>>>>>>>> patch rot removed.
>>>>>>>>
>>>>>>>> I would like to get these pre approved for the next stage 1.
>>>>>>> +      int shift = HOST_BITS_PER_WIDE_INT - (prec &
>>>>>>> (HOST_BITS_PER_WIDE_INT - 1));
>>>>>>>
>>>>>>> I think this should gcc_checking_assert that prec is not out of range
>>>>>>> (any reason why prec is signed int and not unsigned int?) rather than
>>>>>>> ignore bits in prec.
>>>>>>>
>>>>>>> +static inline HOST_WIDE_INT
>>>>>>> +zext_hwi (HOST_WIDE_INT src, int prec)
>>>>>>> +{
>>>>>>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>>>>>>> +    return src;
>>>>>>> +  else
>>>>>>> +    return src & (((HOST_WIDE_INT)1
>>>>>>> +                  << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
>>>>>>> +}
>>>>>>>
>>>>>>> likewise.  Also I'm not sure I agree about the signedness of the
>>>>>>> result
>>>>>>> /
>>>>>>> src.
>>>>>>> zext_hwi (-1, HOST_BITS_PER_WIDE_INT) < 0 is true which is odd.
>>>>>>>
>>>>>>> The patch misses context of uses, so I'm not sure what the above
>>>>>>> functions
>>>>>>> are intended to do.
>>>>>>>
>>>>>>> Richard.
>>>>>>>
>>>>>>>> On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
>>>>>>>>> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>>>>>>>>>
>>>>>>>>>> +# define HOST_HALF_WIDE_INT_PRINT "h"
>>>>>>>>> This may cause problems on hosts not supporting %hd (MinGW?), and
>>>>>>>>> there's
>>>>>>>>> no real need for using "h" here given the promotion of short to int;
>>>>>>>>> you
>>>>>>>>> can just use "" (rather than e.g. needing special handling in
>>>>>>>>> xm-mingw32.h
>>>>>>>>> like is done for HOST_LONG_LONG_FORMAT).
>>>>>>>>>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-03 10:44                                                                               ` Richard Biener
@ 2013-04-03 13:36                                                                                 ` Kenneth Zadeck
  2013-04-03 14:46                                                                                   ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-03 13:36 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor


On 04/03/2013 05:17 AM, Richard Biener wrote:

> In the end you will have a variable-size storage in TREE_INT_CST thus
> you will have at least to emit _code_ copying over meta-data and data
> from the tree representation to the wide-int (similar for RTX CONST_DOUBLE/INT).
> I'm objecting to the amount of code you emit and agree that the runtime
> cost is copying the meta-data (hopefully optimizable via CSE / SRA)
> and in most cases one (or two) iterations of the loop copying the data
> (not optimizable).
i did get rid of the bitsize in the wide-int patch so at this point the 
meta data is the precision and the len.
not really a lot here.   As usual we pay a high price in gcc for not 
pushing the tree rep down into the rtl level, then it would have been 
acceptable to have the tree type bleed into the wide-int code.


>> 2)  You present this as if the implementor actually should care about the
>> implementation and you give 3 alternatives:  the double_int, the current
>> one, and HWI.     We have tried to make it so that the client should not
>> care.   Certainly in my experience here, I have not found a place to care.
> Well, similar as for the copying overhead for tree your approach requires
> overloading operations for HOST_WIDE_INT operands to be able to
> say wi + 1 (which is certainly desirable), or the overhead of using
> wide_int_one ().
>
>> In my opinion double_int needs to go away.  That is the main thrust of my
>> patches.   There is no place in a compiler for an abi that depends on
>> constants fitting into 2 two words whose size is defined by the host.
> That's true.  I'm not arguing to preserve "double-int" - I'm arguing to
> preserve a way to ask for an integer type on the host with (at least)
> N bits.  Almost all double-int users really ask for an integer type on the
> host that has at least as many bits as the pointer representation (or
> word_mode) on
> the target (we do have HOST_WIDEST_INT == 32bits for 64bit pointer
> targets).  No double-int user specifically wants 2 * HOST_WIDE_INT
> precision - that is just what happens to be there.  Thus I am providing
> a way to say get me a host integer with at least N bits (VRP asks for
> this, for example).
>
> What I was asking for is that whatever can provide the above should share
> the functional interface with wide-int (or the othert way around).  And I
> was claiming that wide-int is too fat, because current users of double-int
> eventually store double-ints permanently.
The problem is that, in truth, double int is too fat. 99.something% of 
all constants fit in 1 hwi and that is likely to be true forever (i 
understand that tree vpn may need some thought here).  The rtl level, 
which has, for as long as i have known it, had 2 reps for integer 
constants. So it was relatively easy to slide the CONST_WIDE_INT in.  It 
seems like the right trickery here rather than adding a storage model 
for wide-ints might be a way to use the c++ to invisibly support several 
(and by "several" i really mean 2) classes of TREE_CSTs.

>
>> This is not a beauty contest argument, we have public ports are beginning to
>> use modes that are larger than two x86-64 HWIs and i have a private port
>> that has such modes and it is my experience that any pass that uses this
>> interface has one of three behaviors: it silently gets the wrong answer, it
>> ices, or it fails to do the transformation.  If we leave double_int as an
>> available option, then any use of it potentially will have one of these
>> three behaviors.  And so one of my strong objections to this direction is
>> that i do not want to fight this kind of bug for the rest of my life.
>> Having a single storage model that just always works is in my opinion a
>> highly desirable option.  What you have never answered in a concrete manner
>> is, if we decide to provide this generality, what it would be used for.
>> There is no place in a portable compiler where the right answer for every
>> target is two HOST wide integers.
>>
>> However, i will admit that the HWI option has some merits.   We try to
>> address this in our implementation by dividing what is done inline in
>> wide-int.h to the cases that fit in an HWI and then only drop into the heavy
>> code in wide-int.c if mode is larger (which it rarely will be).   However, a
>> case could be made that for certain kinds of things like string lengths and
>> such, we could use another interface or as you argue, a different storage
>> model with the same interface.   I just do not see that the cost of the
>> conversion code is really going to show up on anyone's radar.
> What's the issue with abstracting away the model so a fixed-size 'len'
> is possible?  (let away the argument that this would easily allow an
> adaptor to tree)
I have a particularly pessimistic perspective because i have already 
written most of this patch.   It is not that i do not want to change 
that code, it is that i have seen a certain set of mistakes that were 
made and i do not want to fix them more than once.   At the rtl level 
you can see the transition from only supporting 32 bit ints to 
supporting 64 bit its to finally supporting two HWIs and that transition 
code is not pretty.  My rtl patch fixes the places where an optimization 
was only made if the data type was 32 bits or smaller as well as the 
places where the optimization was made only if the data type is smaller 
than 64 bits (in addition to fixing all of the places where the code 
ices or simply gets the wrong answer if it is larger than TImode.)  The 
tree level is only modestly better, I believe only because it is newer. 
I have not seen any 32 bit only code, but it is littered with 
transformations that only work for 64 bits.   What is that 64 bit only 
code going to look like in 5 years?

I want to make it easier to write the general code than to write the 
code that only solves the problem for the size port that the implementor 
is currently working on.   So I perceive the storage model as a way to 
keep having to fight this battle forever because it will allow the 
implementor to make a decision that the optimization only needs to be 
done for a particular sized integer.

However, i get the fact that from your perspective, what you really want 
is a solution to the data structure problem in tree-vrp.  My patch for 
tree vrp scans the entire function to find the largest type used in the 
function and then does all of the math at 2x that size.  But i have to 
admit that i thought it was weird that you use tree cst as your long 
term storage.   If this were my pass, i would have allocated a 2d array 
of some type that was as large as the function in 1d and twice as large 
as the largest int used in the other dimension and not overloaded 
tree-cst and then had a set of friend functions in double int to get in 
and out. Of course you do not need friends in double int because the rep 
is exposed, but in wide-int that is now hidden since it now is purely 
functional.

I just have to believe that there is a better way to do tree-vrp than 
messing up wide-int for the rest of the compiler.

>> 3) your trick will work at the tree level, but not at the rtl level.   The
>> wide-int code cannot share storage with the CONST_INTs.    We tried this,
>> and there are a million bugs that would have to be fixed to make it work.
>> It could have worked if CONST_INTs had carried a mode around, but since they
>> do not, you end up with the same CONST_INT sharing the rep for several
>> different types and that just did not work unless you are willing to do
>> substantial cleanups.
> I don't believe you.  I am only asking for the adaptors to tree and RTL to
> work in an RVALUE-ish way (no modification, as obviously RTL and tree
> constants may be shared).  I think your claim is because you have that
> precision and bitsize members in your wide-int which I believe is a
> design red herring.  I suppose we should concentrate on addressing that
> one first.  Thus, let me repeat a few questions on your design to eventually
> let you understand my concerns:
>
> Given two wide-ints, a and b, what precision will the result of
>       a + b
> have?  Consider a having precision 32 and b having precision 64
> on a 32-bit HWI host.
>
> You define wide-int to have no sign information:
>
> +   The representation does not contain any information about
> +   signedness of the represented value, so it can be used to represent
> +   both signed and unsigned numbers.  For operations where the results
> +   depend on signedness (division, comparisons), the signedness must
> +   be specified separately.  For operations where the signness
> +   matters, one of the operands to the operation specifies either
> +   wide_int::SIGNED or wide_int::UNSIGNED.
>
> but the result of operations on mixed precision operands _does_ depend
> on the sign, nevertheless most operations do not get a signedness argument.
> Nor would that help, because it depends on the signedness of the individual
> operands!
>
> double-int get's around this by having a common "precision" to which
> all smaller precision constants have to be sign-/zero-extended.  So
> does CONST_INT and CONST_DOUBLE.
>
> Note that even with same precision you have introduced the same problem
> with the variable len.
>
> My proposal is simple - all wide-ints are signed!  wide-int is basically
> an arbitrary precision signed integer format.  The sign is encoded in
> the most significant bit of the last active HWI of the representation
> (val[len - 1] & (1 << HOST_BITS_PER_WIDE_INT - 1)).  All values
> with less precision than len * HOST_BITS_PER_WIDE_INT are
> properly sign-/zero-extended to precision len * HOST_BITS_PER_WIDE_INT.
>
> This let's you define mixed len operations by implicitely sign-/zero-extending
> the operands to whatever len is required for the operation.
>
> Furthermore it allows you to get rid of the precision member (and
> bitsize anyway).
> Conversion from tree / RTL requires information on the signedness of the
> input (trivial for tree, for RTL all constants are signed - well,
> sign-extended).
> Whenever you want to transfer the wide-int to tree / RTL you have to
> sign-/zero-extend according to the desired precision.  If you need sth else
> than arbitrary precision arithmetic you have to explicitely truncate / extend
> at suitable places - with overflow checking being trivial here.  For
> optimization
> purposes selected operations may benefit from a combined implementation
> receiving a target precision and signedness.  Whatever extra meta-data
> RTL requires does not belong in wide-int but in the RTX.  Trivially
> a mode comes to my mind (on tree we have a type), and trivially
> each RTX has a mode.  And each mode has a precision and bitsize.
> It lacks a sign, so all RTL integer constants are sign-extended for
> encoding efficiency purposes.  mixed-mode operations will not
> occur (mixed len operations will), mixed-mode ops are exclusively
> sign-/zero-extensions and truncations.
>
> Representation of (unsigned HOST_WIDE_INT)-1 would necessarily
> be { 0, (unsigned HOST_WIDE_INT)-1 }, representation of -1 in any
> precision would be { -1 }.
>
> That was my proposal.  Now, can you please properly specify yours?
>
> Thanks,
> Richard.
>
>> On 04/02/2013 11:04 AM, Richard Biener wrote:
>>> On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck
>>> <zadeck@naturalbridge.com> wrote:
>>>> This patch contains a large number of the changes requested by Richi.
>>>> It
>>>> does not contain any of the changes that he requested to abstract the
>>>> storage layer.   That suggestion appears to be quite unworkable.
>>> I of course took this claim as a challenge ... with the following result.
>>> It is
>>> of course quite workable ;)
>>>
>>> The attached patch implements the core wide-int class and three storage
>>> models (fixed size for things like plain HWI and double-int, variable size
>>> similar to how your wide-int works and an adaptor for the double-int as
>>> contained in trees).  With that you can now do
>>>
>>> HOST_WIDE_INT
>>> wi_test (tree x)
>>> {
>>>     // template argument deduction doesn't do the magic we want it to do
>>>     // to make this kind of implicit conversions work
>>>     // overload resolution considers this kind of conversions so we
>>>     // need some magic that combines both ... but seeding the overload
>>>     // set with some instantiations doesn't seem to be possible :/
>>>     // wide_int<> w = x + 1;
>>>     wide_int<> w;
>>>     w += x;
>>>     w += 1;
>>>     // template argument deduction doesn't deduce the return value type,
>>>     // not considering the template default argument either ...
>>>     // w = wi (x) + 1;
>>>     // we could support this by providing rvalue-to-lvalue promotion
>>>     // via a traits class?
>>>     // otoh it would lead to sub-optimal code anyway so we should
>>>     // make the result available as reference parameter and only support
>>>     // wide_int <> res; add (res, x, 1); ?
>>>     w = wi (x).operator+<wide_int<> >(1);
>>>     wide_int<>::add(w, x, 1);
>>>     return w.to_hwi ();
>>> }
>>>
>>> we are somewhat limited with C++ unless we want to get really fancy.
>>> Eventually providing operator+ just doesn't make much sense for
>>> generic wide-int combinations (though then the issue is its operands
>>> are no longer commutative which I think is the case with your wide-int
>>> or double-int as well - they don't suport "1 + wide_int" for obvious
>>> reasons).
>>>
>>> So there are implementation design choices left undecided.
>>>
>>> Oh, and the operation implementations are crap (they compute nonsense).
>>>
>>> But you should get the idea.
>>>
>>> Richard.
>>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch - patch ping for the next stage 1
  2013-04-03 12:21                                                   ` Kenneth Zadeck
@ 2013-04-03 13:38                                                     ` Richard Biener
  2013-04-04  3:13                                                       ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-03 13:38 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Joseph S. Myers, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

On Wed, Apr 3, 2013 at 12:47 PM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
> yes, i had caught that when i merged it in with the patches that used it, is
> it ok aside from that?

Yes.

Thanks,
Richard.

> kenny
>
> On 04/03/2013 05:32 AM, Richard Biener wrote:
>>
>> On Tue, Apr 2, 2013 at 9:08 PM, Kenneth Zadeck <zadeck@naturalbridge.com>
>> wrote:
>>>
>>> this time for sure.
>>
>> Almost ...
>>
>> diff --git a/gcc/hwint.c b/gcc/hwint.c
>> index 330b42c..92d54a3 100644
>> --- a/gcc/hwint.c
>> +++ b/gcc/hwint.c
>> @@ -204,3 +204,35 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT
>> b)
>>   {
>>     return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b));
>>   }
>> +
>> +#ifndef ENABLE_CHECKING
>>
>> #ifdef ENABLE_CHECKING
>>
>> +/* Sign extend SRC starting from PREC.  */
>> +
>> +HOST_WIDE_INT
>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>> +{
>> +  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
>> +
>>
>> Ok with that change.  (maybe catch one random use of the pattern
>> in code and use the helpers - that would have catched this issue)
>>
>> Thanks,
>> Richard.
>>
>>
>>
>>> kenny
>>>
>>> On 04/02/2013 10:54 AM, Richard Biener wrote:
>>>>
>>>> On Tue, Apr 2, 2013 at 3:49 PM, Kenneth Zadeck
>>>> <zadeck@naturalbridge.com>
>>>> wrote:
>>>>>
>>>>> Richard,
>>>>>
>>>>> did everything that you asked here.  bootstrapped and regtested on
>>>>> x86-64.
>>>>> ok to commit?
>>>>
>>>> diff --git a/gcc/hwint.c b/gcc/hwint.c
>>>> index 330b42c..7e5b85c 100644
>>>> --- a/gcc/hwint.c
>>>> +++ b/gcc/hwint.c
>>>> @@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a,
>>>> HOST_WIDE_INT
>>>> b)
>>>>    {
>>>>      return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b));
>>>>    }
>>>> +
>>>> +#ifndef ENABLE_CHECKING
>>>> +/* Sign extend SRC starting from PREC.  */
>>>> +
>>>> +HOST_WIDE_INT
>>>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>>>
>>>> this should go to hwint.h, and without the masking of prec.
>>>> while ...
>>>>
>>>> diff --git a/gcc/hwint.h b/gcc/hwint.h
>>>> index da62fad..9dddf05 100644
>>>> --- a/gcc/hwint.h
>>>> +++ b/gcc/hwint.h
>>>> @@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT,
>>>> HOST_WIDE_INT);
>>>>    extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
>>>>    extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT,
>>>> HOST_WIDE_INT);
>>>>
>>>> +/* Sign extend SRC starting from PREC.  */
>>>> +
>>>> +#ifdef ENABLE_CHECKING
>>>> +extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
>>>> +#else
>>>> +static inline HOST_WIDE_INT
>>>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>>> +{
>>>> +  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
>>>>
>>>> this should go to hwint.c (also without masking prec).
>>>>
>>>> Richard.
>>>>
>>>>
>>>>
>>>>
>>>>> kenny
>>>>>
>>>>>
>>>>> On 04/02/2013 05:38 AM, Richard Biener wrote:
>>>>>>
>>>>>> On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck
>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>
>>>>>>> richard,
>>>>>>>
>>>>>>> I was able to add everything except for the checking asserts.
>>>>>>> While
>>>>>>> I
>>>>>>> think that this is a reasonable idea, it is difficult to add that to
>>>>>>> a
>>>>>>> function that is defined in hwint.h because of circular includes.   I
>>>>>>> could
>>>>>>> move this another file (though this appears to be the logical correct
>>>>>>> place
>>>>>>> for it), or we can do without the asserts.
>>>>>>>
>>>>>>> The context is that [sz]ext_hwi is that are used are over the
>>>>>>> compiler
>>>>>>> but
>>>>>>> are generally written out long.   The wide-int class uses them also,
>>>>>>> but
>>>>>>> wide-int did not see like the right place for them to live and i
>>>>>>> believe
>>>>>>> that you suggested that i move them.
>>>>>>>
>>>>>>> ok to commit, or do you have a suggested resolution to the assert
>>>>>>> issue?
>>>>>>
>>>>>> Yes, do
>>>>>>
>>>>>> #ifdef ENABLE_CHECKING
>>>>>> extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
>>>>>> #else
>>>>>> +/* Sign extend SRC starting from PREC.  */
>>>>>> +
>>>>>> +static inline HOST_WIDE_INT
>>>>>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>>>>> +{
>>>>>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>>>>>> +    return src;
>>>>>> +  else
>>>>>> +    {
>>>>>>            int shift = HOST_BITS_PER_WIDE_INT - prec;
>>>>>> +      return (src << shift) >> shift;
>>>>>> +    }
>>>>>> +}
>>>>>> #endif
>>>>>>
>>>>>> and for ENABLE_CHECKING only provide an out-of-line implementation
>>>>>> in hwint.c.  That's how we did it with abs_hwi (well, we just do not
>>>>>> provide
>>>>>> an inline variant there - that's another possibility).
>>>>>>
>>>>>> Note that hwint.h is always included after config.h so the
>>>>>> ENABLE_CHECKING
>>>>>> definition should be available.
>>>>>>
>>>>>> Richard.
>>>>>>
>>>>>>> kenny
>>>>>>>
>>>>>>>
>>>>>>> On 03/27/2013 10:13 AM, Richard Biener wrote:
>>>>>>>>
>>>>>>>> On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck
>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>
>>>>>>>>> Here is the first of my wide int patches with joseph's comments and
>>>>>>>>> the
>>>>>>>>> patch rot removed.
>>>>>>>>>
>>>>>>>>> I would like to get these pre approved for the next stage 1.
>>>>>>>>
>>>>>>>> +      int shift = HOST_BITS_PER_WIDE_INT - (prec &
>>>>>>>> (HOST_BITS_PER_WIDE_INT - 1));
>>>>>>>>
>>>>>>>> I think this should gcc_checking_assert that prec is not out of
>>>>>>>> range
>>>>>>>> (any reason why prec is signed int and not unsigned int?) rather
>>>>>>>> than
>>>>>>>> ignore bits in prec.
>>>>>>>>
>>>>>>>> +static inline HOST_WIDE_INT
>>>>>>>> +zext_hwi (HOST_WIDE_INT src, int prec)
>>>>>>>> +{
>>>>>>>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>>>>>>>> +    return src;
>>>>>>>> +  else
>>>>>>>> +    return src & (((HOST_WIDE_INT)1
>>>>>>>> +                  << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
>>>>>>>> +}
>>>>>>>>
>>>>>>>> likewise.  Also I'm not sure I agree about the signedness of the
>>>>>>>> result
>>>>>>>> /
>>>>>>>> src.
>>>>>>>> zext_hwi (-1, HOST_BITS_PER_WIDE_INT) < 0 is true which is odd.
>>>>>>>>
>>>>>>>> The patch misses context of uses, so I'm not sure what the above
>>>>>>>> functions
>>>>>>>> are intended to do.
>>>>>>>>
>>>>>>>> Richard.
>>>>>>>>
>>>>>>>>> On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
>>>>>>>>>>
>>>>>>>>>> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>>>>>>>>>>
>>>>>>>>>>> +# define HOST_HALF_WIDE_INT_PRINT "h"
>>>>>>>>>>
>>>>>>>>>> This may cause problems on hosts not supporting %hd (MinGW?), and
>>>>>>>>>> there's
>>>>>>>>>> no real need for using "h" here given the promotion of short to
>>>>>>>>>> int;
>>>>>>>>>> you
>>>>>>>>>> can just use "" (rather than e.g. needing special handling in
>>>>>>>>>> xm-mingw32.h
>>>>>>>>>> like is done for HOST_LONG_LONG_FORMAT).
>>>>>>>>>>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-03 13:36                                                                                 ` Kenneth Zadeck
@ 2013-04-03 14:46                                                                                   ` Richard Biener
  2013-04-03 19:18                                                                                     ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-03 14:46 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On Wed, Apr 3, 2013 at 2:05 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>
> On 04/03/2013 05:17 AM, Richard Biener wrote:
>
>> In the end you will have a variable-size storage in TREE_INT_CST thus
>> you will have at least to emit _code_ copying over meta-data and data
>> from the tree representation to the wide-int (similar for RTX
>> CONST_DOUBLE/INT).
>> I'm objecting to the amount of code you emit and agree that the runtime
>> cost is copying the meta-data (hopefully optimizable via CSE / SRA)
>> and in most cases one (or two) iterations of the loop copying the data
>> (not optimizable).
>
> i did get rid of the bitsize in the wide-int patch so at this point the meta
> data is the precision and the len.
> not really a lot here.   As usual we pay a high price in gcc for not pushing
> the tree rep down into the rtl level, then it would have been acceptable to
> have the tree type bleed into the wide-int code.
>
>
>
>>> 2)  You present this as if the implementor actually should care about the
>>> implementation and you give 3 alternatives:  the double_int, the current
>>> one, and HWI.     We have tried to make it so that the client should not
>>> care.   Certainly in my experience here, I have not found a place to
>>> care.
>>
>> Well, similar as for the copying overhead for tree your approach requires
>> overloading operations for HOST_WIDE_INT operands to be able to
>> say wi + 1 (which is certainly desirable), or the overhead of using
>> wide_int_one ().
>>
>>> In my opinion double_int needs to go away.  That is the main thrust of my
>>> patches.   There is no place in a compiler for an abi that depends on
>>> constants fitting into 2 two words whose size is defined by the host.
>>
>> That's true.  I'm not arguing to preserve "double-int" - I'm arguing to
>> preserve a way to ask for an integer type on the host with (at least)
>> N bits.  Almost all double-int users really ask for an integer type on the
>> host that has at least as many bits as the pointer representation (or
>> word_mode) on
>> the target (we do have HOST_WIDEST_INT == 32bits for 64bit pointer
>> targets).  No double-int user specifically wants 2 * HOST_WIDE_INT
>> precision - that is just what happens to be there.  Thus I am providing
>> a way to say get me a host integer with at least N bits (VRP asks for
>> this, for example).
>>
>> What I was asking for is that whatever can provide the above should share
>> the functional interface with wide-int (or the othert way around).  And I
>> was claiming that wide-int is too fat, because current users of double-int
>> eventually store double-ints permanently.
>
> The problem is that, in truth, double int is too fat. 99.something% of all
> constants fit in 1 hwi and that is likely to be true forever (i understand
> that tree vpn may need some thought here).  The rtl level, which has, for as
> long as i have known it, had 2 reps for integer constants. So it was
> relatively easy to slide the CONST_WIDE_INT in.  It seems like the right
> trickery here rather than adding a storage model for wide-ints might be a
> way to use the c++ to invisibly support several (and by "several" i really
> mean 2) classes of TREE_CSTs.

The truth is that _now_ TREE_INT_CSTs use double-ints and we have
CONST_INT and CONST_DOUBLE.  What I (and you) propose would
get us to use variable-size storage for both, allowing to just use a single
HOST_WIDE_INT in the majority of cases.  In my view the constant
length of the variable-size storage for TREE_INT_CSTs is determined
by its type (thus, it doesn't have "optimized" variable-size storage
but "unoptimized" fixed-size storage based on the maximum storage
requirement for the type).  Similar for RTX CONST_INT which would
have fixed-size storage based on the mode-size of the constant.
Using optimized space (thus using the encoding properties) requires you
to fit the 'short len' somewhere which possibly will not pay off in the end
(for tree we do have that storage available, so we could go with optimized
storage for it, not sure with RTL, I don't see available space there).

>>> This is not a beauty contest argument, we have public ports are beginning
>>> to
>>> use modes that are larger than two x86-64 HWIs and i have a private port
>>> that has such modes and it is my experience that any pass that uses this
>>> interface has one of three behaviors: it silently gets the wrong answer,
>>> it
>>> ices, or it fails to do the transformation.  If we leave double_int as an
>>> available option, then any use of it potentially will have one of these
>>> three behaviors.  And so one of my strong objections to this direction is
>>> that i do not want to fight this kind of bug for the rest of my life.
>>> Having a single storage model that just always works is in my opinion a
>>> highly desirable option.  What you have never answered in a concrete
>>> manner
>>> is, if we decide to provide this generality, what it would be used for.
>>> There is no place in a portable compiler where the right answer for every
>>> target is two HOST wide integers.
>>>
>>> However, i will admit that the HWI option has some merits.   We try to
>>> address this in our implementation by dividing what is done inline in
>>> wide-int.h to the cases that fit in an HWI and then only drop into the
>>> heavy
>>> code in wide-int.c if mode is larger (which it rarely will be).
>>> However, a
>>> case could be made that for certain kinds of things like string lengths
>>> and
>>> such, we could use another interface or as you argue, a different storage
>>> model with the same interface.   I just do not see that the cost of the
>>> conversion code is really going to show up on anyone's radar.
>>
>> What's the issue with abstracting away the model so a fixed-size 'len'
>> is possible?  (let away the argument that this would easily allow an
>> adaptor to tree)
>
> I have a particularly pessimistic perspective because i have already written
> most of this patch.   It is not that i do not want to change that code, it
> is that i have seen a certain set of mistakes that were made and i do not
> want to fix them more than once.   At the rtl level you can see the
> transition from only supporting 32 bit ints to supporting 64 bit its to
> finally supporting two HWIs and that transition code is not pretty.  My rtl
> patch fixes the places where an optimization was only made if the data type
> was 32 bits or smaller as well as the places where the optimization was made
> only if the data type is smaller than 64 bits (in addition to fixing all of
> the places where the code ices or simply gets the wrong answer if it is
> larger than TImode.)  The tree level is only modestly better, I believe only
> because it is newer. I have not seen any 32 bit only code, but it is
> littered with transformations that only work for 64 bits.   What is that 64
> bit only code going to look like in 5 years?

The user interface of wide-int does not depend on whether a storage model
is abstracted or not.  If you take advantage of the storage model by
making its interface leaner then it will.  But I guess converting everything
before settling on the wide-int interface may not have been the wisest
choice in the end (providing a wide-int that can literally replace double-int
would have got you testing coverage without any change besides
double-int.[ch] and wide-int.[ch]).

> I want to make it easier to write the general code than to write the code
> that only solves the problem for the size port that the implementor is
> currently working on.   So I perceive the storage model as a way to keep
> having to fight this battle forever because it will allow the implementor to
> make a decision that the optimization only needs to be done for a particular
> sized integer.
>
> However, i get the fact that from your perspective, what you really want is
> a solution to the data structure problem in tree-vrp.

No, that's just a convenient example.  What I really want is a wide-int
that is less visibly a replacement for CONST_DOUBLE.

>  My patch for tree vrp
> scans the entire function to find the largest type used in the function and
> then does all of the math at 2x that size.  But i have to admit that i
> thought it was weird that you use tree cst as your long term storage.   If
> this were my pass, i would have allocated a 2d array of some type that was
> as large as the function in 1d and twice as large as the largest int used in
> the other dimension and not overloaded tree-cst and then had a set of friend
> functions in double int to get in and out. Of course you do not need friends
> in double int because the rep is exposed, but in wide-int that is now hidden
> since it now is purely functional.
>
> I just have to believe that there is a better way to do tree-vrp than
> messing up wide-int for the rest of the compiler.

It's not "messing up", it's making wide-int a generally useful thing and
not tying it so closely to RTL.

>>> 3) your trick will work at the tree level, but not at the rtl level.
>>> The
>>> wide-int code cannot share storage with the CONST_INTs.    We tried this,
>>> and there are a million bugs that would have to be fixed to make it work.
>>> It could have worked if CONST_INTs had carried a mode around, but since
>>> they
>>> do not, you end up with the same CONST_INT sharing the rep for several
>>> different types and that just did not work unless you are willing to do
>>> substantial cleanups.
>>
>> I don't believe you.  I am only asking for the adaptors to tree and RTL to
>> work in an RVALUE-ish way (no modification, as obviously RTL and tree
>> constants may be shared).  I think your claim is because you have that
>> precision and bitsize members in your wide-int which I believe is a
>> design red herring.  I suppose we should concentrate on addressing that
>> one first.  Thus, let me repeat a few questions on your design to
>> eventually
>> let you understand my concerns:
>>
>> Given two wide-ints, a and b, what precision will the result of
>>       a + b
>> have?  Consider a having precision 32 and b having precision 64
>> on a 32-bit HWI host.
>>
>> You define wide-int to have no sign information:
>>
>> +   The representation does not contain any information about
>> +   signedness of the represented value, so it can be used to represent
>> +   both signed and unsigned numbers.  For operations where the results
>> +   depend on signedness (division, comparisons), the signedness must
>> +   be specified separately.  For operations where the signness
>> +   matters, one of the operands to the operation specifies either
>> +   wide_int::SIGNED or wide_int::UNSIGNED.
>>
>> but the result of operations on mixed precision operands _does_ depend
>> on the sign, nevertheless most operations do not get a signedness
>> argument.
>> Nor would that help, because it depends on the signedness of the
>> individual
>> operands!
>>
>> double-int get's around this by having a common "precision" to which
>> all smaller precision constants have to be sign-/zero-extended.  So
>> does CONST_INT and CONST_DOUBLE.
>>
>> Note that even with same precision you have introduced the same problem
>> with the variable len.
>>
>> My proposal is simple - all wide-ints are signed!  wide-int is basically
>> an arbitrary precision signed integer format.  The sign is encoded in
>> the most significant bit of the last active HWI of the representation
>> (val[len - 1] & (1 << HOST_BITS_PER_WIDE_INT - 1)).  All values
>> with less precision than len * HOST_BITS_PER_WIDE_INT are
>> properly sign-/zero-extended to precision len * HOST_BITS_PER_WIDE_INT.
>>
>> This let's you define mixed len operations by implicitely
>> sign-/zero-extending
>> the operands to whatever len is required for the operation.
>>
>> Furthermore it allows you to get rid of the precision member (and
>> bitsize anyway).
>> Conversion from tree / RTL requires information on the signedness of the
>> input (trivial for tree, for RTL all constants are signed - well,
>> sign-extended).
>> Whenever you want to transfer the wide-int to tree / RTL you have to
>> sign-/zero-extend according to the desired precision.  If you need sth
>> else
>> than arbitrary precision arithmetic you have to explicitely truncate /
>> extend
>> at suitable places - with overflow checking being trivial here.  For
>> optimization
>> purposes selected operations may benefit from a combined implementation
>> receiving a target precision and signedness.  Whatever extra meta-data
>> RTL requires does not belong in wide-int but in the RTX.  Trivially
>> a mode comes to my mind (on tree we have a type), and trivially
>> each RTX has a mode.  And each mode has a precision and bitsize.
>> It lacks a sign, so all RTL integer constants are sign-extended for
>> encoding efficiency purposes.  mixed-mode operations will not
>> occur (mixed len operations will), mixed-mode ops are exclusively
>> sign-/zero-extensions and truncations.
>>
>> Representation of (unsigned HOST_WIDE_INT)-1 would necessarily
>> be { 0, (unsigned HOST_WIDE_INT)-1 }, representation of -1 in any
>> precision would be { -1 }.
>>
>> That was my proposal.  Now, can you please properly specify yours?

And you chose to not answer that fundamental question of how your
wide-int is _supposed_ to work?  Ok, maybe I shouldn't have distracted
you with the bits before this.

Richard.

>> Thanks,
>> Richard.
>>
>>> On 04/02/2013 11:04 AM, Richard Biener wrote:
>>>>
>>>> On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck
>>>> <zadeck@naturalbridge.com> wrote:
>>>>>
>>>>> This patch contains a large number of the changes requested by Richi.
>>>>> It
>>>>> does not contain any of the changes that he requested to abstract the
>>>>> storage layer.   That suggestion appears to be quite unworkable.
>>>>
>>>> I of course took this claim as a challenge ... with the following
>>>> result.
>>>> It is
>>>> of course quite workable ;)
>>>>
>>>> The attached patch implements the core wide-int class and three storage
>>>> models (fixed size for things like plain HWI and double-int, variable
>>>> size
>>>> similar to how your wide-int works and an adaptor for the double-int as
>>>> contained in trees).  With that you can now do
>>>>
>>>> HOST_WIDE_INT
>>>> wi_test (tree x)
>>>> {
>>>>     // template argument deduction doesn't do the magic we want it to do
>>>>     // to make this kind of implicit conversions work
>>>>     // overload resolution considers this kind of conversions so we
>>>>     // need some magic that combines both ... but seeding the overload
>>>>     // set with some instantiations doesn't seem to be possible :/
>>>>     // wide_int<> w = x + 1;
>>>>     wide_int<> w;
>>>>     w += x;
>>>>     w += 1;
>>>>     // template argument deduction doesn't deduce the return value type,
>>>>     // not considering the template default argument either ...
>>>>     // w = wi (x) + 1;
>>>>     // we could support this by providing rvalue-to-lvalue promotion
>>>>     // via a traits class?
>>>>     // otoh it would lead to sub-optimal code anyway so we should
>>>>     // make the result available as reference parameter and only support
>>>>     // wide_int <> res; add (res, x, 1); ?
>>>>     w = wi (x).operator+<wide_int<> >(1);
>>>>     wide_int<>::add(w, x, 1);
>>>>     return w.to_hwi ();
>>>> }
>>>>
>>>> we are somewhat limited with C++ unless we want to get really fancy.
>>>> Eventually providing operator+ just doesn't make much sense for
>>>> generic wide-int combinations (though then the issue is its operands
>>>> are no longer commutative which I think is the case with your wide-int
>>>> or double-int as well - they don't suport "1 + wide_int" for obvious
>>>> reasons).
>>>>
>>>> So there are implementation design choices left undecided.
>>>>
>>>> Oh, and the operation implementations are crap (they compute nonsense).
>>>>
>>>> But you should get the idea.
>>>>
>>>> Richard.
>>>
>>>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-03 14:46                                                                                   ` Richard Biener
@ 2013-04-03 19:18                                                                                     ` Kenneth Zadeck
  2013-04-04 11:45                                                                                       ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-03 19:18 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On 04/03/2013 09:53 AM, Richard Biener wrote:
> On Wed, Apr 3, 2013 at 2:05 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> On 04/03/2013 05:17 AM, Richard Biener wrote:
>>
>>> In the end you will have a variable-size storage in TREE_INT_CST thus
>>> you will have at least to emit _code_ copying over meta-data and data
>>> from the tree representation to the wide-int (similar for RTX
>>> CONST_DOUBLE/INT).
>>> I'm objecting to the amount of code you emit and agree that the runtime
>>> cost is copying the meta-data (hopefully optimizable via CSE / SRA)
>>> and in most cases one (or two) iterations of the loop copying the data
>>> (not optimizable).
>> i did get rid of the bitsize in the wide-int patch so at this point the meta
>> data is the precision and the len.
>> not really a lot here.   As usual we pay a high price in gcc for not pushing
>> the tree rep down into the rtl level, then it would have been acceptable to
>> have the tree type bleed into the wide-int code.
>>
>>
>>
>>>> 2)  You present this as if the implementor actually should care about the
>>>> implementation and you give 3 alternatives:  the double_int, the current
>>>> one, and HWI.     We have tried to make it so that the client should not
>>>> care.   Certainly in my experience here, I have not found a place to
>>>> care.
>>> Well, similar as for the copying overhead for tree your approach requires
>>> overloading operations for HOST_WIDE_INT operands to be able to
>>> say wi + 1 (which is certainly desirable), or the overhead of using
>>> wide_int_one ().
>>>
>>>> In my opinion double_int needs to go away.  That is the main thrust of my
>>>> patches.   There is no place in a compiler for an abi that depends on
>>>> constants fitting into 2 two words whose size is defined by the host.
>>> That's true.  I'm not arguing to preserve "double-int" - I'm arguing to
>>> preserve a way to ask for an integer type on the host with (at least)
>>> N bits.  Almost all double-int users really ask for an integer type on the
>>> host that has at least as many bits as the pointer representation (or
>>> word_mode) on
>>> the target (we do have HOST_WIDEST_INT == 32bits for 64bit pointer
>>> targets).  No double-int user specifically wants 2 * HOST_WIDE_INT
>>> precision - that is just what happens to be there.  Thus I am providing
>>> a way to say get me a host integer with at least N bits (VRP asks for
>>> this, for example).
>>>
>>> What I was asking for is that whatever can provide the above should share
>>> the functional interface with wide-int (or the othert way around).  And I
>>> was claiming that wide-int is too fat, because current users of double-int
>>> eventually store double-ints permanently.
>> The problem is that, in truth, double int is too fat. 99.something% of all
>> constants fit in 1 hwi and that is likely to be true forever (i understand
>> that tree vpn may need some thought here).  The rtl level, which has, for as
>> long as i have known it, had 2 reps for integer constants. So it was
>> relatively easy to slide the CONST_WIDE_INT in.  It seems like the right
>> trickery here rather than adding a storage model for wide-ints might be a
>> way to use the c++ to invisibly support several (and by "several" i really
>> mean 2) classes of TREE_CSTs.
> The truth is that _now_ TREE_INT_CSTs use double-ints and we have
> CONST_INT and CONST_DOUBLE.  What I (and you) propose would
> get us to use variable-size storage for both, allowing to just use a single
> HOST_WIDE_INT in the majority of cases.  In my view the constant
> length of the variable-size storage for TREE_INT_CSTs is determined
> by its type (thus, it doesn't have "optimized" variable-size storage
> but "unoptimized" fixed-size storage based on the maximum storage
> requirement for the type).  Similar for RTX CONST_INT which would
> have fixed-size storage based on the mode-size of the constant.
> Using optimized space (thus using the encoding properties) requires you
> to fit the 'short len' somewhere which possibly will not pay off in the end
> (for tree we do have that storage available, so we could go with optimized
> storage for it, not sure with RTL, I don't see available space there).
There are two questions here:   one is the fact that you object to the 
fact that we represent small constants efficiently and the second is 
that we take advantage of the fact that fixed size stack allocation is 
effectively free for short lived objects like wide-ints (as i use them).

At the rtl level your idea does not work.   rtl constants do not have a 
mode or type.    So if you do not compress, how are you going to 
determine how many words you need for the constant 1.   I would love to 
have a rep that had the mode in it.    But it is a huge change that 
requires a lot of hacking to every port.

I understand that this makes me vulnerable to the argument that we 
should not let the rtl level ever dictate anything about the tree level, 
but the truth is that a variable len rep is almost always used for big 
integers.   In our code, most constants of large types are small 
numbers.   (Remember i got into this because the tree constant prop 
thinks that left shifting any number by anything greater than 128 is 
always 0 and discovered that that was just the tip of the iceberg.) But 
mostly i support the decision to canonize numbers to the smallest number 
of HWIs because most of the algorithms to do the math can be short 
circuited.    I admit that if i had to effectively unpack most numbers 
to do the math, that the canonization would be a waste.   However, this 
is not really relevant to this conversation.   Yes, you could get rid of 
the len, but this such a small part of picture.

Furthermore, I am constrained at the rtl level because it is just too 
dirty to share the storage.   We tried that and the amount of whack a 
mole we were playing was killing us.

I am comfortable making big changes at the portable level because i can 
easily test them, but changes to fundamental data structures inside 
every port is more than i am willing to do.   If you are going to do 
that, then you are going to have start giving rtl constants modes and 
that is a huge change (that while desirable i cannot do).

At the tree level you could share the storage, I admit that that is 
easy, i just do not think that it is desirable.  The stack allocation 
inside the wide-int is very cheap and the fact that the number that 
comes out is almost always one hwi makes this very efficient.   Even if 
I was starting from scratch this would be a strong contender to be the 
right representation.

Fundamentally, i do not believe that the amount of copying that i am 
proposing at the tree level will be significant.  Yes, if you force me 
to use an uncompressed format you can make what i propose expensive.

>>>> This is not a beauty contest argument, we have public ports are beginning
>>>> to
>>>> use modes that are larger than two x86-64 HWIs and i have a private port
>>>> that has such modes and it is my experience that any pass that uses this
>>>> interface has one of three behaviors: it silently gets the wrong answer,
>>>> it
>>>> ices, or it fails to do the transformation.  If we leave double_int as an
>>>> available option, then any use of it potentially will have one of these
>>>> three behaviors.  And so one of my strong objections to this direction is
>>>> that i do not want to fight this kind of bug for the rest of my life.
>>>> Having a single storage model that just always works is in my opinion a
>>>> highly desirable option.  What you have never answered in a concrete
>>>> manner
>>>> is, if we decide to provide this generality, what it would be used for.
>>>> There is no place in a portable compiler where the right answer for every
>>>> target is two HOST wide integers.
>>>>
>>>> However, i will admit that the HWI option has some merits.   We try to
>>>> address this in our implementation by dividing what is done inline in
>>>> wide-int.h to the cases that fit in an HWI and then only drop into the
>>>> heavy
>>>> code in wide-int.c if mode is larger (which it rarely will be).
>>>> However, a
>>>> case could be made that for certain kinds of things like string lengths
>>>> and
>>>> such, we could use another interface or as you argue, a different storage
>>>> model with the same interface.   I just do not see that the cost of the
>>>> conversion code is really going to show up on anyone's radar.
>>> What's the issue with abstracting away the model so a fixed-size 'len'
>>> is possible?  (let away the argument that this would easily allow an
>>> adaptor to tree)
>> I have a particularly pessimistic perspective because i have already written
>> most of this patch.   It is not that i do not want to change that code, it
>> is that i have seen a certain set of mistakes that were made and i do not
>> want to fix them more than once.   At the rtl level you can see the
>> transition from only supporting 32 bit ints to supporting 64 bit its to
>> finally supporting two HWIs and that transition code is not pretty.  My rtl
>> patch fixes the places where an optimization was only made if the data type
>> was 32 bits or smaller as well as the places where the optimization was made
>> only if the data type is smaller than 64 bits (in addition to fixing all of
>> the places where the code ices or simply gets the wrong answer if it is
>> larger than TImode.)  The tree level is only modestly better, I believe only
>> because it is newer. I have not seen any 32 bit only code, but it is
>> littered with transformations that only work for 64 bits.   What is that 64
>> bit only code going to look like in 5 years?
> The user interface of wide-int does not depend on whether a storage model
> is abstracted or not.  If you take advantage of the storage model by
> making its interface leaner then it will.  But I guess converting everything
> before settling on the wide-int interface may not have been the wisest
> choice in the end (providing a wide-int that can literally replace double-int
> would have got you testing coverage without any change besides
> double-int.[ch] and wide-int.[ch]).
I think that it was exactly the correct decision.   We have made 
significant changes to the structure as we have gone along.   I have 
basically done most of what you have suggested, (the interface is 
completely functional, i got rid of the bitsize...)   What you are 
running into is that mike stump, richard sandiford and myself actually 
believe that the storage model is a fundamentally bad idea.

>> I want to make it easier to write the general code than to write the code
>> that only solves the problem for the size port that the implementor is
>> currently working on.   So I perceive the storage model as a way to keep
>> having to fight this battle forever because it will allow the implementor to
>> make a decision that the optimization only needs to be done for a particular
>> sized integer.
>>
>> However, i get the fact that from your perspective, what you really want is
>> a solution to the data structure problem in tree-vrp.
> No, that's just a convenient example.  What I really want is a wide-int
> that is less visibly a replacement for CONST_DOUBLE.
I think that that is unfair.   Variable length reps are the standard 
technique for doing wide math.  I am just proposing using data 
structures that are common best practices in the rest of the world and 
adapting them so that they match the gcc world better than just hacking 
in a gmp interface.
>
>>   My patch for tree vrp
>> scans the entire function to find the largest type used in the function and
>> then does all of the math at 2x that size.  But i have to admit that i
>> thought it was weird that you use tree cst as your long term storage.   If
>> this were my pass, i would have allocated a 2d array of some type that was
>> as large as the function in 1d and twice as large as the largest int used in
>> the other dimension and not overloaded tree-cst and then had a set of friend
>> functions in double int to get in and out. Of course you do not need friends
>> in double int because the rep is exposed, but in wide-int that is now hidden
>> since it now is purely functional.
>>
>> I just have to believe that there is a better way to do tree-vrp than
>> messing up wide-int for the rest of the compiler.
> It's not "messing up", it's making wide-int a generally useful thing and
> not tying it so closely to RTL.
Again, this is unfair.
>
>>>> 3) your trick will work at the tree level, but not at the rtl level.
>>>> The
>>>> wide-int code cannot share storage with the CONST_INTs.    We tried this,
>>>> and there are a million bugs that would have to be fixed to make it work.
>>>> It could have worked if CONST_INTs had carried a mode around, but since
>>>> they
>>>> do not, you end up with the same CONST_INT sharing the rep for several
>>>> different types and that just did not work unless you are willing to do
>>>> substantial cleanups.
>>> I don't believe you.  I am only asking for the adaptors to tree and RTL to
>>> work in an RVALUE-ish way (no modification, as obviously RTL and tree
>>> constants may be shared).  I think your claim is because you have that
>>> precision and bitsize members in your wide-int which I believe is a
>>> design red herring.  I suppose we should concentrate on addressing that
>>> one first.  Thus, let me repeat a few questions on your design to
>>> eventually
>>> let you understand my concerns:
>>>
>>> Given two wide-ints, a and b, what precision will the result of
>>>        a + b
>>> have?  Consider a having precision 32 and b having precision 64
>>> on a 32-bit HWI host.
>>>
>>> You define wide-int to have no sign information:
>>>
>>> +   The representation does not contain any information about
>>> +   signedness of the represented value, so it can be used to represent
>>> +   both signed and unsigned numbers.  For operations where the results
>>> +   depend on signedness (division, comparisons), the signedness must
>>> +   be specified separately.  For operations where the signness
>>> +   matters, one of the operands to the operation specifies either
>>> +   wide_int::SIGNED or wide_int::UNSIGNED.
>>>
>>> but the result of operations on mixed precision operands _does_ depend
>>> on the sign, nevertheless most operations do not get a signedness
>>> argument.
>>> Nor would that help, because it depends on the signedness of the
>>> individual
>>> operands!
>>>
>>> double-int get's around this by having a common "precision" to which
>>> all smaller precision constants have to be sign-/zero-extended.  So
>>> does CONST_INT and CONST_DOUBLE.
>>>
>>> Note that even with same precision you have introduced the same problem
>>> with the variable len.
>>>
>>> My proposal is simple - all wide-ints are signed!  wide-int is basically
>>> an arbitrary precision signed integer format.  The sign is encoded in
>>> the most significant bit of the last active HWI of the representation
>>> (val[len - 1] & (1 << HOST_BITS_PER_WIDE_INT - 1)).  All values
>>> with less precision than len * HOST_BITS_PER_WIDE_INT are
>>> properly sign-/zero-extended to precision len * HOST_BITS_PER_WIDE_INT.
>>>
>>> This let's you define mixed len operations by implicitely
>>> sign-/zero-extending
>>> the operands to whatever len is required for the operation.
>>>
>>> Furthermore it allows you to get rid of the precision member (and
>>> bitsize anyway).
>>> Conversion from tree / RTL requires information on the signedness of the
>>> input (trivial for tree, for RTL all constants are signed - well,
>>> sign-extended).
>>> Whenever you want to transfer the wide-int to tree / RTL you have to
>>> sign-/zero-extend according to the desired precision.  If you need sth
>>> else
>>> than arbitrary precision arithmetic you have to explicitely truncate /
>>> extend
>>> at suitable places - with overflow checking being trivial here.  For
>>> optimization
>>> purposes selected operations may benefit from a combined implementation
>>> receiving a target precision and signedness.  Whatever extra meta-data
>>> RTL requires does not belong in wide-int but in the RTX.  Trivially
>>> a mode comes to my mind (on tree we have a type), and trivially
>>> each RTX has a mode.  And each mode has a precision and bitsize.
>>> It lacks a sign, so all RTL integer constants are sign-extended for
>>> encoding efficiency purposes.  mixed-mode operations will not
>>> occur (mixed len operations will), mixed-mode ops are exclusively
>>> sign-/zero-extensions and truncations.
>>>
>>> Representation of (unsigned HOST_WIDE_INT)-1 would necessarily
>>> be { 0, (unsigned HOST_WIDE_INT)-1 }, representation of -1 in any
>>> precision would be { -1 }.
>>>
>>> That was my proposal.  Now, can you please properly specify yours?
> And you chose to not answer that fundamental question of how your
> wide-int is _supposed_ to work?  Ok, maybe I shouldn't have distracted
> you with the bits before this.
sorry, i missed this question by accident.

we did not do infinite precision by design.   We looked at the set of 
programming languages that gcc either compiles or might compile and we 
looked at the set of machines that gcc targets and neither of these two 
sets of entities define their operations in terms of infinite precision 
math.   They always do math within a particular precision.    Scripting 
languages do use infinite precision but gcc does not compile any of 
them.   So unless you are going to restrict your set of operations to 
those that satisfy the properties of a ring, it is generally not 
strictly safe to do your math in infinite precision.

we do all of the math in the precision defined by the types or modes 
that are passed in.

constants are defined to be the size of the precision unless they can be 
compressed.   The len field tells how many words are actually needed to 
exactly represent the constant if (len-1)*HOST_WIDE_BITS_PER_WIDE_INT is 
less than the precision. The decompression process is to add a number of 
words to the high order side of the number.   These words must contain a 
zero if the highest represented bit is 0 and -1 if the highest 
represented bit is 1.

i.e. this looks a lot like sign extension, but the numbers them selves 
are not inherently signed or unsigned as in your representation.    It 
is up to the operators to imply the signess. So the unsigned multiply 
operation is different than the signed multiply operation.    But these 
are applied to the bits without an interpretation of their sign.

> Richard.
>
>>> Thanks,
>>> Richard.
>>>
>>>> On 04/02/2013 11:04 AM, Richard Biener wrote:
>>>>> On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck
>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>> This patch contains a large number of the changes requested by Richi.
>>>>>> It
>>>>>> does not contain any of the changes that he requested to abstract the
>>>>>> storage layer.   That suggestion appears to be quite unworkable.
>>>>> I of course took this claim as a challenge ... with the following
>>>>> result.
>>>>> It is
>>>>> of course quite workable ;)
>>>>>
>>>>> The attached patch implements the core wide-int class and three storage
>>>>> models (fixed size for things like plain HWI and double-int, variable
>>>>> size
>>>>> similar to how your wide-int works and an adaptor for the double-int as
>>>>> contained in trees).  With that you can now do
>>>>>
>>>>> HOST_WIDE_INT
>>>>> wi_test (tree x)
>>>>> {
>>>>>      // template argument deduction doesn't do the magic we want it to do
>>>>>      // to make this kind of implicit conversions work
>>>>>      // overload resolution considers this kind of conversions so we
>>>>>      // need some magic that combines both ... but seeding the overload
>>>>>      // set with some instantiations doesn't seem to be possible :/
>>>>>      // wide_int<> w = x + 1;
>>>>>      wide_int<> w;
>>>>>      w += x;
>>>>>      w += 1;
>>>>>      // template argument deduction doesn't deduce the return value type,
>>>>>      // not considering the template default argument either ...
>>>>>      // w = wi (x) + 1;
>>>>>      // we could support this by providing rvalue-to-lvalue promotion
>>>>>      // via a traits class?
>>>>>      // otoh it would lead to sub-optimal code anyway so we should
>>>>>      // make the result available as reference parameter and only support
>>>>>      // wide_int <> res; add (res, x, 1); ?
>>>>>      w = wi (x).operator+<wide_int<> >(1);
>>>>>      wide_int<>::add(w, x, 1);
>>>>>      return w.to_hwi ();
>>>>> }
>>>>>
>>>>> we are somewhat limited with C++ unless we want to get really fancy.
>>>>> Eventually providing operator+ just doesn't make much sense for
>>>>> generic wide-int combinations (though then the issue is its operands
>>>>> are no longer commutative which I think is the case with your wide-int
>>>>> or double-int as well - they don't suport "1 + wide_int" for obvious
>>>>> reasons).
>>>>>
>>>>> So there are implementation design choices left undecided.
>>>>>
>>>>> Oh, and the operation implementations are crap (they compute nonsense).
>>>>>
>>>>> But you should get the idea.
>>>>>
>>>>> Richard.
>>>>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - first small patch - patch ping for the next stage 1
  2013-04-03 13:38                                                     ` Richard Biener
@ 2013-04-04  3:13                                                       ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-04  3:13 UTC (permalink / raw)
  To: Richard Biener
  Cc: Joseph S. Myers, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

committed as revision 197456

kenny
On 04/03/2013 08:05 AM, Richard Biener wrote:
> On Wed, Apr 3, 2013 at 12:47 PM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> yes, i had caught that when i merged it in with the patches that used it, is
>> it ok aside from that?
> Yes.
>
> Thanks,
> Richard.
>
>> kenny
>>
>> On 04/03/2013 05:32 AM, Richard Biener wrote:
>>> On Tue, Apr 2, 2013 at 9:08 PM, Kenneth Zadeck <zadeck@naturalbridge.com>
>>> wrote:
>>>> this time for sure.
>>> Almost ...
>>>
>>> diff --git a/gcc/hwint.c b/gcc/hwint.c
>>> index 330b42c..92d54a3 100644
>>> --- a/gcc/hwint.c
>>> +++ b/gcc/hwint.c
>>> @@ -204,3 +204,35 @@ least_common_multiple (HOST_WIDE_INT a, HOST_WIDE_INT
>>> b)
>>>    {
>>>      return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b));
>>>    }
>>> +
>>> +#ifndef ENABLE_CHECKING
>>>
>>> #ifdef ENABLE_CHECKING
>>>
>>> +/* Sign extend SRC starting from PREC.  */
>>> +
>>> +HOST_WIDE_INT
>>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>> +{
>>> +  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
>>> +
>>>
>>> Ok with that change.  (maybe catch one random use of the pattern
>>> in code and use the helpers - that would have catched this issue)
>>>
>>> Thanks,
>>> Richard.
>>>
>>>
>>>
>>>> kenny
>>>>
>>>> On 04/02/2013 10:54 AM, Richard Biener wrote:
>>>>> On Tue, Apr 2, 2013 at 3:49 PM, Kenneth Zadeck
>>>>> <zadeck@naturalbridge.com>
>>>>> wrote:
>>>>>> Richard,
>>>>>>
>>>>>> did everything that you asked here.  bootstrapped and regtested on
>>>>>> x86-64.
>>>>>> ok to commit?
>>>>> diff --git a/gcc/hwint.c b/gcc/hwint.c
>>>>> index 330b42c..7e5b85c 100644
>>>>> --- a/gcc/hwint.c
>>>>> +++ b/gcc/hwint.c
>>>>> @@ -204,3 +204,33 @@ least_common_multiple (HOST_WIDE_INT a,
>>>>> HOST_WIDE_INT
>>>>> b)
>>>>>     {
>>>>>       return mul_hwi (abs_hwi (a) / gcd (a, b), abs_hwi (b));
>>>>>     }
>>>>> +
>>>>> +#ifndef ENABLE_CHECKING
>>>>> +/* Sign extend SRC starting from PREC.  */
>>>>> +
>>>>> +HOST_WIDE_INT
>>>>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>>>>
>>>>> this should go to hwint.h, and without the masking of prec.
>>>>> while ...
>>>>>
>>>>> diff --git a/gcc/hwint.h b/gcc/hwint.h
>>>>> index da62fad..9dddf05 100644
>>>>> --- a/gcc/hwint.h
>>>>> +++ b/gcc/hwint.h
>>>>> @@ -276,4 +316,42 @@ extern HOST_WIDE_INT pos_mul_hwi (HOST_WIDE_INT,
>>>>> HOST_WIDE_INT);
>>>>>     extern HOST_WIDE_INT mul_hwi (HOST_WIDE_INT, HOST_WIDE_INT);
>>>>>     extern HOST_WIDE_INT least_common_multiple (HOST_WIDE_INT,
>>>>> HOST_WIDE_INT);
>>>>>
>>>>> +/* Sign extend SRC starting from PREC.  */
>>>>> +
>>>>> +#ifdef ENABLE_CHECKING
>>>>> +extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
>>>>> +#else
>>>>> +static inline HOST_WIDE_INT
>>>>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>>>> +{
>>>>> +  gcc_checking_assert (prec <= HOST_BITS_PER_WIDE_INT);
>>>>>
>>>>> this should go to hwint.c (also without masking prec).
>>>>>
>>>>> Richard.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> kenny
>>>>>>
>>>>>>
>>>>>> On 04/02/2013 05:38 AM, Richard Biener wrote:
>>>>>>> On Sun, Mar 31, 2013 at 7:51 PM, Kenneth Zadeck
>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>> richard,
>>>>>>>>
>>>>>>>> I was able to add everything except for the checking asserts.
>>>>>>>> While
>>>>>>>> I
>>>>>>>> think that this is a reasonable idea, it is difficult to add that to
>>>>>>>> a
>>>>>>>> function that is defined in hwint.h because of circular includes.   I
>>>>>>>> could
>>>>>>>> move this another file (though this appears to be the logical correct
>>>>>>>> place
>>>>>>>> for it), or we can do without the asserts.
>>>>>>>>
>>>>>>>> The context is that [sz]ext_hwi is that are used are over the
>>>>>>>> compiler
>>>>>>>> but
>>>>>>>> are generally written out long.   The wide-int class uses them also,
>>>>>>>> but
>>>>>>>> wide-int did not see like the right place for them to live and i
>>>>>>>> believe
>>>>>>>> that you suggested that i move them.
>>>>>>>>
>>>>>>>> ok to commit, or do you have a suggested resolution to the assert
>>>>>>>> issue?
>>>>>>> Yes, do
>>>>>>>
>>>>>>> #ifdef ENABLE_CHECKING
>>>>>>> extern HOST_WIDE_INT sext_hwi (HOST_WIDE_INT, unsigned int);
>>>>>>> #else
>>>>>>> +/* Sign extend SRC starting from PREC.  */
>>>>>>> +
>>>>>>> +static inline HOST_WIDE_INT
>>>>>>> +sext_hwi (HOST_WIDE_INT src, unsigned int prec)
>>>>>>> +{
>>>>>>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>>>>>>> +    return src;
>>>>>>> +  else
>>>>>>> +    {
>>>>>>>             int shift = HOST_BITS_PER_WIDE_INT - prec;
>>>>>>> +      return (src << shift) >> shift;
>>>>>>> +    }
>>>>>>> +}
>>>>>>> #endif
>>>>>>>
>>>>>>> and for ENABLE_CHECKING only provide an out-of-line implementation
>>>>>>> in hwint.c.  That's how we did it with abs_hwi (well, we just do not
>>>>>>> provide
>>>>>>> an inline variant there - that's another possibility).
>>>>>>>
>>>>>>> Note that hwint.h is always included after config.h so the
>>>>>>> ENABLE_CHECKING
>>>>>>> definition should be available.
>>>>>>>
>>>>>>> Richard.
>>>>>>>
>>>>>>>> kenny
>>>>>>>>
>>>>>>>>
>>>>>>>> On 03/27/2013 10:13 AM, Richard Biener wrote:
>>>>>>>>> On Wed, Feb 27, 2013 at 1:22 AM, Kenneth Zadeck
>>>>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>>>> Here is the first of my wide int patches with joseph's comments and
>>>>>>>>>> the
>>>>>>>>>> patch rot removed.
>>>>>>>>>>
>>>>>>>>>> I would like to get these pre approved for the next stage 1.
>>>>>>>>> +      int shift = HOST_BITS_PER_WIDE_INT - (prec &
>>>>>>>>> (HOST_BITS_PER_WIDE_INT - 1));
>>>>>>>>>
>>>>>>>>> I think this should gcc_checking_assert that prec is not out of
>>>>>>>>> range
>>>>>>>>> (any reason why prec is signed int and not unsigned int?) rather
>>>>>>>>> than
>>>>>>>>> ignore bits in prec.
>>>>>>>>>
>>>>>>>>> +static inline HOST_WIDE_INT
>>>>>>>>> +zext_hwi (HOST_WIDE_INT src, int prec)
>>>>>>>>> +{
>>>>>>>>> +  if (prec == HOST_BITS_PER_WIDE_INT)
>>>>>>>>> +    return src;
>>>>>>>>> +  else
>>>>>>>>> +    return src & (((HOST_WIDE_INT)1
>>>>>>>>> +                  << (prec & (HOST_BITS_PER_WIDE_INT - 1))) - 1);
>>>>>>>>> +}
>>>>>>>>>
>>>>>>>>> likewise.  Also I'm not sure I agree about the signedness of the
>>>>>>>>> result
>>>>>>>>> /
>>>>>>>>> src.
>>>>>>>>> zext_hwi (-1, HOST_BITS_PER_WIDE_INT) < 0 is true which is odd.
>>>>>>>>>
>>>>>>>>> The patch misses context of uses, so I'm not sure what the above
>>>>>>>>> functions
>>>>>>>>> are intended to do.
>>>>>>>>>
>>>>>>>>> Richard.
>>>>>>>>>
>>>>>>>>>> On 10/05/2012 08:14 PM, Joseph S. Myers wrote:
>>>>>>>>>>> On Fri, 5 Oct 2012, Kenneth Zadeck wrote:
>>>>>>>>>>>
>>>>>>>>>>>> +# define HOST_HALF_WIDE_INT_PRINT "h"
>>>>>>>>>>> This may cause problems on hosts not supporting %hd (MinGW?), and
>>>>>>>>>>> there's
>>>>>>>>>>> no real need for using "h" here given the promotion of short to
>>>>>>>>>>> int;
>>>>>>>>>>> you
>>>>>>>>>>> can just use "" (rather than e.g. needing special handling in
>>>>>>>>>>> xm-mingw32.h
>>>>>>>>>>> like is done for HOST_LONG_LONG_FORMAT).
>>>>>>>>>>>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-03-27 14:54                                                                           ` Richard Biener
@ 2013-04-04  8:08                                                                             ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-04  8:08 UTC (permalink / raw)
  To: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl,
	Richard Sandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 8166 bytes --]

richard,

in the places where i delete your comments, it is because i did this and 
there is no further discussion.


On 03/27/2013 10:54 AM, Richard Biener wrote:

> this also shows the main reason I was asking for storage abstraction.
> The initialization from tree is way too expensive.
We have discussed this on the other thread.
> +/* Convert a integer cst into a wide int expanded to BITSIZE and
> +   PRECISION.  This call is used by tree passes like vrp that expect
> +   that the math is done in an infinite precision style.  BITSIZE and
> +   PRECISION are generally determined to be twice the largest type
> +   seen in the function.  */
> +
> +wide_int
> +wide_int::from_tree_as_infinite_precision (const_tree tcst,
> +                                          unsigned int bitsize,
> +                                          unsigned int precision)
> +{
>
> I know you have converted everything, but to make this patch reviewable
> I'd like you to strip the initial wide_int down to a bare minimum.
>
> Only then people will have a reasonable chance to play with interface
> changes (such as providing a storage abstraction).
I do not really know what you mean here.    While I understand that you 
have an idea of a pure aesthetic for an abstraction, I come from the 
school where the abstractions are chosen based on the needs of the 
clients.  I see no advantage to allow you to say that this or that you 
do not find appealing can just go away without considering that there 
may be many actual places where this turns out to be exactly the correct 
abstraction.
> +/* Check the upper HOST_WIDE_INTs of src to see if the length can be
> +   shortened.  An upper HOST_WIDE_INT is unnecessary if it is all ones
> +   or zeros and the top bit of the next lower word matches.
> +
> +   This function may change the representation of THIS, but does not
> +   change the value that THIS represents.  It does not sign extend in
> +   the case that the size of the mode is less than
> +   HOST_BITS_PER_WIDE_INT.  */
> +
> +void
> +wide_int::canonize ()
>
> this shouldn't be necessary - it's an optimization - and due to value
> semantics (yes - I know you have a weird mix of value semantics
> and modify-in-place in wide_int) the new length should be computed
> transparently when creating a new value.
First, we took your advice several iterations of these patches ago.    
There is no more modify in place semantics!!!!   Everything is 
completely functional.   The canonize function is needed because there 
is a specific definition of what wide-ints look like, and this maintains 
that if we cannot prove that it is already canonized from the operation.


> +  unsigned short len;
> +  unsigned int bitsize;
> +  unsigned int precision;
I removed the bitsize as a persistent field.    now it has to be passed 
into the shift operations, the only place that needed that information.


> I see we didn't get away with this mix of bitsize and precision.  I'm probably
> going to try revisit the past discussions - but can you point me to a single
> place in the RTL conversion where they make a difference?  Bits beyond
> precision are either undefined or properly zero-/sign-extended.  Implicit
> extension beyond len val members should then provide in "valid" bits
> up to bitsize (if anyone cares).  That's how double-ints work on tree
> INTGER_CSTs
> which only care for precision, even with partial integer mode types
> (ok, I never came along one of these beasts - testcase / target?).
>
> [abstraction possibility - have both wide_ints with actual mode and
> wide_ints with arbitrary bitsize/precision]
>
> +  enum ShiftOp {
> +    NONE,
> +    /* There are two uses for the wide-int shifting functions.  The
> +       first use is as an emulation of the target hardware.  The
> +       second use is as service routines for other optimizations.  The
> +       first case needs to be identified by passing TRUNC as the value
> +       of ShiftOp so that shift amount is properly handled according to the
> +       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
> +       amount is always truncated by the bytesize of the mode of
> +       THIS.  */
> +    TRUNC
> +  };
>
> I think I have expressed my opinion on this.  (and SHIFT_COUNT_TRUNCATED
> should vanish - certainly wide-int shouldn't care, so doesn't double-int)
I understand that double int does not care, and i happen to think that 
that is a problem.   I happen to work on three platforms where 
SHIFT_COUNT_TRUNCATED is not true and while I understand that this is 
not important for the x86, it is important that for my platforms, this 
be done consistently throughout the compiler.   The double_int rep tries 
to maintain the illusion that it is doing things in infinite precision.  
The problem is that this is not the way the rest of the compiler 
works.   What i am trying to do is to make the compiler behave exactly 
the same way, no matter which level the transformation is applied.   We 
tell the ports that we support SHIFT_COUNT_TRUNCATED and so we need to 
either completely do it or not make that promise.





> +  enum SignOp {
> +    /* Many of the math functions produce different results depending
> +       on if they are SIGNED or UNSIGNED.  In general, there are two
> +       different functions, whose names are prefixed with an 'S" and
> +       or an 'U'.  However, for some math functions there is also a
> +       routine that does not have the prefix and takes an SignOp
> +       parameter of SIGNED or UNSIGNED.  */
> +    SIGNED,
> +    UNSIGNED
> +  };
>
> See above.  GCC standard practice is a 'unsigned uns' parameter.
I understand that there is a large body of code that has a lot of 0s and 
1s as various parameters.   is there any underlying problem with trying 
to make the more mnemonic?   I personally find, and i think that most 
people will agree that interfaces with a lot of required 0s and 1s very 
bad programming style.

> +  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type);
> +  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type,
> +                                  bool *overflow);
> +  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode);
> +  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode,
> +                                   bool *overflow);
> +  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0,
> +                                   enum machine_mode mode);
> +  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0,
> +                                   enum machine_mode mode,
> +                                   bool *overflow);
>
> way too many overloads.  Besides the "raw" ones I only expect wide-ints
> to be constructed from a tree INTEGER_CST or a rtx DOUBLE_INT.

I see that for example in wide_int::add bitsize and precision are arbitrarily
copied from the first operand.  With the present way of dealing with them
it would sound more logical to assert that they are the same for both
operands (do both need to match?).  I'd rather see wide-int being
"arbitrary" precision/bitsize up to its supported storage size (as
double-int is).
I suppose we've been there and discussed this to death already though ;)
As you have some fused operation plus sign-/zero-extend ops already
the alternative is to always provide a precision for the result and treat the
operands as "arbitrary" precision (that way wide_int::minus_one can
simply return a sign-extended precision 1 -1).

Btw, wide_int::add does not look at bitsize at all, so it clearly is redundant
information.  Grepping for uses of bitsize shows up only maintaining and
copying around this information as well.  please remove bitsize.

bitsize is gone.    I have added asserts so that for the symmetric 
binary operations like add, sub, mul there is a check that the precision 
of both operands is the same.    for asymmetric operations like shift, 
the shift amount can be any size operand and for them it is perfectly 
proper to copy them from the first parameter.


> Ok, enough for today.
>
> Thanks,
> Richard.
>
>> kenny
>>


[-- Attachment #2: p4-5.diff --]
[-- Type: text/x-patch, Size: 130851 bytes --]

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 19377a9..a12bc05 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -856,7 +856,7 @@ COMMON_TARGET_DEF_H = common/common-target-def.h \
 RTL_BASE_H = coretypes.h rtl.h rtl.def $(MACHMODE_H) reg-notes.def \
   insn-notes.def $(INPUT_H) $(REAL_H) statistics.h $(VEC_H) \
   $(FIXED_VALUE_H) alias.h $(HASHTAB_H)
-FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h
+FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h wide-int.h
 RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h
 RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H)
 READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
@@ -868,7 +868,7 @@ INTERNAL_FN_H = internal-fn.h $(INTERNAL_FN_DEF)
 TREE_H = coretypes.h tree.h all-tree.def tree.def c-family/c-common.def \
 	$(lang_tree_files) $(MACHMODE_H) tree-check.h $(BUILTINS_DEF) \
 	$(INPUT_H) statistics.h $(VEC_H) treestruct.def $(HASHTAB_H) \
-	double-int.h alias.h $(SYMTAB_H) $(FLAGS_H) \
+	double-int.h wide-int.h alias.h $(SYMTAB_H) $(FLAGS_H) \
 	$(REAL_H) $(FIXED_VALUE_H)
 REGSET_H = regset.h $(BITMAP_H) hard-reg-set.h
 BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) \
@@ -1458,6 +1458,7 @@ OBJS = \
 	varpool.o \
 	vmsdbgout.o \
 	web.o \
+	wide-int.o \
 	xcoffout.o \
 	$(out_object_file) \
 	$(EXTRA_OBJS) \
@@ -2686,6 +2687,7 @@ targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
    tree-ssa-alias.h $(TREE_FLOW_H)
 common/common-targhooks.o : common/common-targhooks.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(INPUT_H) $(TM_H) $(COMMON_TARGET_H) common/common-targhooks.h
+wide-int.o: wide-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
 
 bversion.h: s-bversion; @true
 s-bversion: BASE-VER
@@ -3939,15 +3941,16 @@ CFLAGS-gengtype-parse.o += -DGENERATOR_FILE
 build/gengtype-parse.o: $(BCONFIG_H)
 
 gengtype-state.o build/gengtype-state.o: gengtype-state.c $(SYSTEM_H) \
-  gengtype.h errors.h double-int.h version.h $(HASHTAB_H) $(OBSTACK_H) \
-  $(XREGEX_H)
+  gengtype.h errors.h double-int.h wide-int.h version.h $(HASHTAB_H)    \
+  $(OBSTACK_H) $(XREGEX_H)
 gengtype-state.o: $(CONFIG_H)
 CFLAGS-gengtype-state.o += -DGENERATOR_FILE
 build/gengtype-state.o: $(BCONFIG_H)
+wide-int.h: $(GTM_H) insn-modes.h
 
 gengtype.o build/gengtype.o : gengtype.c $(SYSTEM_H) gengtype.h 	\
-  rtl.def insn-notes.def errors.h double-int.h version.h $(HASHTAB_H) \
-  $(OBSTACK_H) $(XREGEX_H)
+  rtl.def insn-notes.def errors.h double-int.h wide-int.h version.h     \
+  $(HASHTAB_H) $(OBSTACK_H) $(XREGEX_H)
 gengtype.o: $(CONFIG_H)
 CFLAGS-gengtype.o += -DGENERATOR_FILE
 build/gengtype.o: $(BCONFIG_H)
diff --git a/gcc/wide-int.c b/gcc/wide-int.c
new file mode 100644
index 0000000..3a1cc7c
--- /dev/null
+++ b/gcc/wide-int.c
@@ -0,0 +1,3067 @@
+/* Operations with very long integers.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hwint.h"
+#include "wide-int.h"
+#include "rtl.h"
+#include "tree.h"
+#include "dumpfile.h"
+
+// using wide_int::;
+
+/* This is the maximal size of the buffer needed for dump.  */
+const int MAX_SIZE = 4 * (MAX_BITSIZE_MODE_ANY_INT / 4
+		     + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
+
+/*
+ * Internal utilities.
+ */
+
+/* Quantities to deal with values that hold half of a wide int.  Used
+   in multiply and divide.  */
+#define HALF_INT_MASK (((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1)
+
+#define BLOCK_OF(TARGET) ((TARGET) / HOST_BITS_PER_WIDE_INT)
+#define BLOCKS_NEEDED(PREC) \
+  (((PREC) + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+
+/*
+ * Conversion routines in and out of wide-int.
+ */
+
+/* Convert OP0 into a wide int of PRECISION.  If the precision is less
+   than HOST_BITS_PER_WIDE_INT, zero extend the value of the word.
+   The overflow bit are set if the number was too large to fit in the
+   mode.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0,
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT t = sext_hwi (op0, precision);
+      if (t != op0 && overflow)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+  result.len = 1;
+
+  return result;
+}
+
+/* Convert OP0 into a wide int of PRECISION.  If the precision is less
+   than HOST_BITS_PER_WIDE_INT, zero extend the value of the word.
+   The overflow bit are set if the number was too large to fit in the
+   mode.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, 
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT t = zext_hwi (op0, precision);
+      if (t != op0 && overflow)
+	*overflow = true;
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && precision > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+  return result;
+}
+
+/* Create a wide_int from an array of host_wide_ints in OP1 of LEN.
+   The result has PRECISION.  */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT *op1, unsigned int len, 
+		      unsigned int precision)
+{
+  unsigned int i;
+  wide_int result;
+  
+  result.len = len;
+  result.precision = precision;
+
+  for (i=0; i < len; i++)
+    result.val[i] = op1[i];
+
+  result.canonize ();
+  return result;
+}
+
+/* Convert a double int into a wide int with precision PREC.  */
+
+wide_int
+wide_int::from_double_int (double_int di, unsigned int prec)
+{
+  HOST_WIDE_INT op = di.low;
+  wide_int result;
+
+  result.precision = prec;
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result.val[0] = sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    result.val[1] = sext_hwi (di.high, prec);
+	  else
+	    result.val[1] = di.high;
+	}
+    }
+
+  if (result.len == 2)
+    result.canonize ();
+
+  return result;
+}
+
+/* Convert a integer cst into a wide int.  */
+
+wide_int
+wide_int::from_tree (const_tree tcst)
+{
+  wide_int result;
+  tree type = TREE_TYPE (tcst);
+  unsigned int prec = TYPE_PRECISION (type);
+  HOST_WIDE_INT op = TREE_INT_CST_LOW (tcst);
+
+  result.precision = prec;
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    {
+      if (TYPE_UNSIGNED (type))
+	result.val[0] = zext_hwi (op, prec);
+      else
+	result.val[0] = sext_hwi (op, prec);
+    }
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  op = TREE_INT_CST_HIGH (tcst);
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    {
+	      if (TYPE_UNSIGNED (type))
+		result.val[1] = zext_hwi (op, prec - HOST_BITS_PER_WIDE_INT);
+	      else
+		result.val[1] = sext_hwi (op, prec - HOST_BITS_PER_WIDE_INT);
+	    }
+	  else
+	    result.val[1] = op;
+	}
+    }
+ 
+  return result;
+}
+
+/* Extract a constant integer from the X of type MODE.  The bits of
+   the integer are returned.  */
+
+wide_int
+wide_int::from_rtx (const_rtx x, enum machine_mode mode)
+{
+  wide_int result;
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  gcc_assert (mode != VOIDmode);
+
+  result.precision = prec;
+
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+      if ((prec & (HOST_BITS_PER_WIDE_INT - 1)) != 0)
+	result.val[0] = sext_hwi (INTVAL (x), prec);
+      else
+	result.val[0] = INTVAL (x);
+      result.len = 1;
+      break;
+
+#if TARGET_SUPPORTS_WIDE_INT
+    case CONST_WIDE_INT:
+      {
+	int i;
+	result.len = CONST_WIDE_INT_NUNITS (x);
+	
+	for (i = 0; i < result.len; i++)
+	  result.val[i] = CONST_WIDE_INT_ELT (x, i);
+      }
+      break;
+#else
+    case CONST_DOUBLE:
+      result.len = 2;
+      result.val[0] = CONST_DOUBLE_LOW (x);
+      result.val[1] = CONST_DOUBLE_HIGH (x);
+      result.canonize ();
+      break;
+#endif
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return result;
+}
+
+/* Construct from a buffer of length LEN.  BUFFER will be read according
+   to byte endianess and word endianess.  Only the lower LEN bytes
+   of the result are set; the remaining high bytes are cleared.  */
+
+wide_int
+wide_int::from_buffer (const unsigned char *buffer, int len)
+{
+  wide_int result = wide_int::zero (len * BITS_PER_UNIT);
+  int words = len / UNITS_PER_WORD;
+
+  for (int byte = 0; byte < len; byte++)
+    {
+      int offset;
+      int index;
+      int bitpos = byte * BITS_PER_UNIT;
+      unsigned HOST_WIDE_INT value;
+
+      if (len > UNITS_PER_WORD)
+	{
+	  int word = byte / UNITS_PER_WORD;
+
+	  if (WORDS_BIG_ENDIAN)
+	    word = (words - 1) - word;
+
+	  offset = word * UNITS_PER_WORD;
+
+	  if (BYTES_BIG_ENDIAN)
+	    offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
+	  else
+	    offset += byte % UNITS_PER_WORD;
+	}
+      else
+	offset = BYTES_BIG_ENDIAN ? (len - 1) - byte : byte;
+
+      value = (unsigned HOST_WIDE_INT) buffer[offset];
+
+      index = bitpos / HOST_BITS_PER_WIDE_INT;
+      result.val[index] |= value << bitpos;
+    }
+
+  result.canonize ();
+  return result;
+}
+
+
+/*
+ * Largest and smallest values in a mode.
+ */
+
+/* Produce the largest SGNed number that is represented in PREC.  The
+   resulting number is placed in a wide int of size PRECISION.  */
+
+wide_int
+wide_int::max_value (unsigned int prec, unsigned int precision, 
+		     SignOp sgn)
+{
+  wide_int result;
+  
+  result.precision = precision;
+
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned max is just all ones, for which the compressed
+	 rep is just a single HWI.  */ 
+      result.len = 1;
+      result.val[0] = (HOST_WIDE_INT)-1;
+    }
+  else
+    {
+      /* The signed max is all ones except the top bit.  This must be
+	 explicitly represented.  */
+      int i;
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      int shift = (small_prec == 0) 
+	? HOST_BITS_PER_WIDE_INT - 1 : small_prec - 1;
+
+      result.len = BLOCKS_NEEDED (prec);
+      for (i = 0; i < result.len - 1; i++)
+	result.val[i] = (HOST_WIDE_INT)-1;
+
+      result.val[result.len - 1] = ((HOST_WIDE_INT)1 << shift) - 1;
+    }
+  
+  return result;
+}
+
+/* Produce the smallest SGNed number that is represented in PREC.  The
+   resulting number is placed in a wide int of size PRECISION.  */
+
+wide_int
+wide_int::min_value (unsigned int prec, unsigned int precision, 
+		     SignOp sgn)
+{
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned min is just all zeros, for which the compressed
+	 rep is just a single HWI.  */ 
+      wide_int result;
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = 0;
+      return result;
+    }
+  else
+    {
+      /* The signed min is all zeros except the top bit.  This must be
+	 explicitly represented.  */
+      return set_bit_in_zero (prec - 1, precision);
+    }
+}
+
+/*
+ * Public utilities.
+ */
+
+/* Check the upper HOST_WIDE_INTs of src to see if the length can be
+   shortened.  An upper HOST_WIDE_INT is unnecessary if it is all ones
+   or zeros and the top bit of the next lower word matches.
+
+   This function may change the representation of THIS, but does not
+   change the value that THIS represents.  It does not sign extend in
+   the case that the size of the mode is less than
+   HOST_BITS_PER_WIDE_INT.  */
+
+void
+wide_int::canonize ()
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT top;
+  int i;
+
+  if (len > blocks_needed)
+    len = blocks_needed;
+
+  /* Clean up the top bits for any mode that is not a multiple of a HWI.  */
+  if (len == blocks_needed && small_prec)
+    val[len - 1] = sext_hwi (val[len - 1], small_prec);
+
+  if (len == 1)
+    return;
+
+  top = val[len - 1];
+  if (top != 0 && top != (HOST_WIDE_INT)-1)
+    return;
+
+  /* At this point we know that the top is either 0 or -1.  Find the
+     first block that is not a copy of this.  */
+  for (i = len - 2; i >= 0; i--)
+    {
+      HOST_WIDE_INT x = val[i];
+      if (x != top)
+	{
+	  if (x >> (HOST_BITS_PER_WIDE_INT - 1) == top)
+	    {
+	      len = i + 1;
+	      return;
+	    }
+
+	  /* We need an extra block because the top bit block i does
+	     not match the extension.  */
+	  len = i + 2;
+	  return;
+	}
+    }
+
+  /* The number is 0 or -1.  */
+  len = 1;
+}
+
+
+/* Make a copy of this.  */
+
+wide_int
+wide_int::copy () const
+{
+  wide_int result;
+  int i;
+
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+  return result;
+}
+
+
+/* Copy THIS replacing the precision with PREC.
+   It can do any of truncation, extension or copying.  */
+
+wide_int
+wide_int::force_to_size (unsigned int prec, SignOp sgn) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (prec);
+  int i;
+
+  result.precision = prec;
+  result.len = blocks_needed < len ? blocks_needed : len;
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+
+  if (prec >= precision) 
+    {
+      /* Expanding */
+      int small_precision = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+      /* The only case we care about is unsigned because the rep is
+	 inherantly signed.  */
+      if (sgn == UNSIGNED)
+	{
+	  /* The top block in the existing rep must be zero extended,
+	     but this is all the work we need to do.  */
+	  if (small_precision 
+	      && (len == BLOCKS_NEEDED (precision)
+		  || len == blocks_needed))
+	    result.val[len-1] = zext_hwi (result.val[len-1], small_precision);
+	  else if (len == BLOCKS_NEEDED (precision) 
+		   && len < blocks_needed
+		   && small_precision == 0
+		   && result.val[result.len - 1] < 0)
+		    /* We need to put the 0 block on top to keep the value
+		       from being sign extended.  */ 
+		    result.val[result.len++] = 0;
+	}
+    }
+  else
+    {
+      /* Truncating.  */
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      /* The only weird case we need to look at here is when we are
+         truncating within the top block.  We need to make sure that
+         everything in the block above the new precision is sign
+         extended.  Note that this is independent of the SGN.  This is
+         just to stay canonical.  */
+      if (small_prec && (blocks_needed == len))
+	result.val[blocks_needed-1]
+	  = sext_hwi (result.val[blocks_needed-1], small_prec);
+    }
+
+  return result;
+}
+
+/*
+ * public printing routines.
+ */
+
+/* Try to print the signed self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_DEC, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decs (buf);
+  fputs (buf, file);
+}
+
+/* Try to print the unsigned self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decu (buf);
+  fputs (buf, file);
+}
+
+void 
+wide_int::print_hex (char *buf) const
+{
+  int i = len;
+
+  if (zero_p ())
+    sprintf (buf, "0x");
+  else
+    {
+      if (neg_p ())
+	{
+	  int j;
+	  /* If the number is negative, we may need to pad value with
+	     0xFFF...  because the leading elements may be missing and
+	     we do not print a '-' with hex.  */
+	  for (j = BLOCKS_NEEDED (precision); j > i; j--)
+	    buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, (HOST_WIDE_INT) -1);
+	    
+	}
+      else
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_HEX, val [--i]);
+      while (-- i >= 0)
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, val [i]);
+    }
+}
+
+/* Print one big hex number to FILE.  Note that some assemblers may not
+   accept this for large modes.  */
+void 
+wide_int::print_hex (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_hex (buf);
+  fputs (buf, file);
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently singed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+bool
+wide_int::eq_p_large (const wide_int &op1) const
+{
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  while (l0 > l1)
+    if (val[l0--] != op1.sign_mask ())
+      return false;
+
+  while (l1 > l0)
+    if (op1.val[l1--] != sign_mask ())
+      return false;
+
+  while (l0 >= 0)
+    if (val[l0--] != op1.val[l1--])
+      return false;
+
+  return true;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p_large (const wide_int &op1) const
+{
+  int l;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  int blocks_needed = BLOCKS_NEEDED (precision);
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == len ? val [blocks_needed - 1] : sign_mask ();
+  s1 = blocks_needed == op1.len ? op1.val [blocks_needed - 1] : op1.sign_mask ();
+  if (s0 < s1)
+    return true;
+  if (s0 > s1)
+    return false;
+
+  l = MAX (len, op1.len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < len ? val [l] : sign_mask ();
+      u1 = l < op1.len ? op1.val [l] : op1.sign_mask ();
+
+      if (u0 < u1)
+	return true;
+      if (u0 > u1)
+	return false;
+      l--;
+    }
+
+  return false;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+int
+wide_int::cmps_large (const wide_int &op1) const
+{
+  int l;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  int blocks_needed = BLOCKS_NEEDED (precision);
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == len ? val [blocks_needed - 1] : sign_mask ();
+  s1 = blocks_needed == op1.len ? op1.val [blocks_needed - 1] : op1.sign_mask ();
+  if (s0 < s1)
+    return -1;
+  if (s0 > s1)
+    return 1;
+
+  l = MAX (len, op1.len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < len ? val [l] : sign_mask ();
+      u1 = l < op1.len ? op1.val [l] : op1.sign_mask ();
+
+      if (u0 < u1)
+	return -1;
+      if (u0 > u1)
+	return 1;
+      l--;
+    }
+
+  return 0;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p_large (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1.sign_mask ();
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  while (l1 > l0)
+    {
+      x0 = sign_mask ();
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  return false;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+int
+wide_int::cmpu_large (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1.sign_mask ();
+      if (x0 < x1)
+	return -1;
+      else if (x0 > x1)
+	return 1;
+    }
+
+  while (l1 > l0)
+    {
+      x0 = sign_mask ();
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	return -1;
+      if (x0 > x1)
+	return 1;
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1.val[l1--];
+      if (x0 < x1)
+	return -1;
+      if (x0 > x1)
+	return 1;
+    }
+
+  return 0;
+}
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p (unsigned int prec) const
+{
+  int i;
+  HOST_WIDE_INT x;
+  int small_prec;
+  bool result;
+
+  if (BLOCKS_NEEDED (prec) != len)
+    {
+      result = false;
+      goto ex;
+    }
+
+  for (i=0; i < len - 1; i++)
+    if (val[i] != 0)
+      {
+	result = false;
+	goto ex;
+      }
+
+  x = val[len - 1];
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec)
+    x = x << (HOST_BITS_PER_WIDE_INT - small_prec);
+
+  result = x == ((HOST_WIDE_INT)1) << (HOST_BITS_PER_WIDE_INT - 1);
+
+ ex:
+  return result;
+}
+
+/* Returns true if THIS fits into range of TYPE.  Signedness of OP0 is
+   assumed to be the same as the signedness of TYPE.  */
+
+bool
+wide_int::fits_to_tree_p (const_tree type) const
+{
+  int type_prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return fits_u_p (type_prec);
+  else
+    return fits_s_p (type_prec);
+}
+
+/* Returns true of THIS fits in the unsigned range of precision.  */
+
+bool
+wide_int::fits_s_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == sext (prec);
+}
+
+
+/* Returns true if THIS fits into range of TYPE.  */
+
+bool
+wide_int::fits_u_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == zext (prec);
+}
+
+/*
+ * Extension.
+ */
+
+/* Sign extend THIS starting at OFFSET.  The precision of the result
+   are the same as THIS.  */
+
+wide_int
+wide_int::sext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = sext_hwi (val[0], offset);
+      else
+	/* If offset is greater or equal to precision there is nothing
+	   to do since the internal rep is already sign extended.  */
+	result.val[0] = val[0];
+
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, precision);
+      
+      /* Now we can do the real sign extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      if (off)
+	{
+	  int block = BLOCK_OF (offset);
+	  result.val[block] = sext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      /* We never need an extra element for sign extended values.  */
+    }    
+
+  return result;
+}
+
+/* Zero extend THIS starting at OFFSET.  The precision of the result
+   are the same as THIS.  */
+
+wide_int
+wide_int::zext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+  int block;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = zext_hwi (val[0], offset);
+      else if (offset == precision)
+	result.val[0] = val[0];
+	/* If offset was greater than the precision we need to zero
+	   extend from the old precision since the internal rep was
+	   equivalent to sign extended.  */
+      else
+	result.val[0] = zext_hwi (val[0], precision);
+	
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, precision);
+
+      /* Now we can do the real zero extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      block = BLOCK_OF (offset);
+      if (off)
+	{
+	  result.val[block] = zext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      else
+	/* See if we need an extra zero element to satisfy the
+	   compression rule.  */
+	if (val[block - 1] < 0 && offset < precision)
+	  {
+	    result.val[block] = 0;
+	    result.len += 1;
+	  }
+    }
+  return result;
+}
+
+/*
+ * Masking, inserting, shifting, rotating.
+ */
+
+/* Return a value with a one bit inserted in THIS at BITPOS.  */
+
+wide_int
+wide_int::set_bit (unsigned int bitpos) const
+{
+  wide_int result;
+  int i, j;
+
+  if (bitpos >= precision)
+    result = copy ();
+  else
+    {
+      result = decompress (bitpos, precision);
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+  return result;
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with PRECISION.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, unsigned int prec)
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (bitpos + 1);
+  int i, j;
+
+  result.precision = prec;
+  if (bitpos >= prec)
+    {
+      result.len = 1;
+      result.val[0] = 0;
+    }
+  else
+    {
+      result.len = blocks_needed;
+      for (i = 0; i < blocks_needed; i++)
+	result.val[i] = 0;
+      
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+  return result;
+}
+
+/* Insert WIDTH bits from OP0 into THIS starting at START.  */
+
+wide_int
+wide_int::insert (const wide_int &op0, unsigned int start, 
+		  unsigned int width) const
+{
+  wide_int result;
+  wide_int mask;
+  wide_int tmp;
+
+  if (start + width >= precision) 
+    width = precision - start;
+
+  mask = shifted_mask (start, width, false, precision);
+  tmp = op0.lshift (start, precision, NONE);
+  result = tmp & mask;
+
+  tmp = and_not (mask);
+  result = result | tmp;
+
+  return result;
+}
+
+/* bswap THIS.  */
+
+wide_int
+wide_int::bswap () const
+{
+  wide_int result;
+  int i, s;
+  int end;
+  int len = BLOCKS_NEEDED (precision);
+
+  /* This is not a well defined operation if the precision is not a
+     multiple of 8.  */
+  gcc_assert ((precision & 0x7) == 0);
+
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < len; i++)
+    result.val[i] = 0;
+
+  /* Only swap the bytes that are not the padding.  */
+  if ((precision & (HOST_BITS_PER_WIDE_INT - 1))
+      && (this->len == len))
+    end = precision;
+  else
+    end = this->len * HOST_BITS_PER_WIDE_INT;
+
+  for (s = 0; s < end; s += 8)
+    {
+      unsigned int d = precision - s - 8;
+      unsigned HOST_WIDE_INT byte;
+
+      int block = s / HOST_BITS_PER_WIDE_INT;
+      int offset = s & (HOST_BITS_PER_WIDE_INT - 1);
+
+      byte = (val[block] >> offset) & 0xff;
+
+      block = d / HOST_BITS_PER_WIDE_INT;
+      offset = d & (HOST_BITS_PER_WIDE_INT - 1);
+
+      result.val[block] |= byte << offset;
+    }
+
+  result.canonize ();
+
+  return result;
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with PREC. */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  int shift;
+
+  gcc_assert (width < 2 * MAX_BITSIZE_MODE_ANY_INT);
+  gcc_assert (prec <= 2 * MAX_BITSIZE_MODE_ANY_INT);
+
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (prec);
+      else
+	result = wide_int::zero (prec);
+      return result;
+    }
+
+  result.precision = prec;
+
+  while (i < width / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = width & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      HOST_WIDE_INT last = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~last : last;
+    }
+  result.len = i;
+
+  return result;
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  */
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  unsigned int shift;
+  unsigned int end = start + width;
+  HOST_WIDE_INT block;
+
+  if (start + width > prec)
+    width = prec - start;
+ 
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (prec);
+      else
+	result = wide_int::zero (prec);
+      return result;
+    }
+
+  result.precision = prec;
+
+  while (i < start / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? (HOST_WIDE_INT)-1 : 0;
+
+  shift = start & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift)
+    {
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      shift = (end) & (HOST_BITS_PER_WIDE_INT - 1);
+      if (shift)
+	{
+	  /* case 000111000 */
+	  block = (((HOST_WIDE_INT)1) << shift) - block - 1;
+	  result.val[i++] = negate ? ~block : block;
+	  result.len = i;
+
+	  return result;
+	}
+      else
+	/* ...111000 */
+	result.val[i++] = negate ? block : ~block;
+    }
+
+  while (i < end / HOST_BITS_PER_WIDE_INT)
+    /* 1111111 */
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = end & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      /* 000011111 */
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~block : block;
+    }
+
+  result.len = i;
+
+  return result;
+}
+
+
+/*
+ * logical operations.
+ */
+
+/* Return THIS & OP1.  */
+
+wide_int
+wide_int::and_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Return THIS & ~OP1.  */
+
+wide_int
+wide_int::and_not_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & ~op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+wide_int
+wide_int::or_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+  return result;
+}
+
+/* Return THIS | ~OP1.  */
+
+wide_int
+wide_int::or_not_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1.len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (op1.sign_mask () == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1.val[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | ~op1.val[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Return the exclusive ior (xor) of THIS and OP1.  */
+
+wide_int
+wide_int::xor_large (const wide_int &op1) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1.len - 1;
+
+  result.len = MAX (len, op1.len);
+  result.precision = precision;
+
+  while (l0 > l1)
+    {
+      result.val[l0] = val[l0] ^ op1.sign_mask ();
+      l0--;
+    }
+
+  while (l1 > l0)
+    {
+      result.val[l1] = sign_mask () ^ op1.val[l1];
+      l1--;
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] ^ op1.val[l0];
+      l0--;
+    }
+
+  result.canonize ();
+
+  return result;
+}
+
+/*
+ * math
+ */
+
+/* Absolute value of THIS.  */
+
+wide_int
+wide_int::abs () const
+{
+  if (sign_mask ())
+    return neg ();
+
+  wide_int result = copy ();
+  return result;
+}
+
+/* Add of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::add_large (const wide_int &op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1.len ? (unsigned HOST_WIDE_INT)op1.val[i] : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 + mask1 + carry;
+      result.len++;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/* Add of OP0 and OP1 with overflow checking.  If the result overflows
+   within the precision, set OVERFLOW.  OVERFLOW is assumed to be
+   sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::add (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT old_carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int i, small_prec;
+
+  gcc_checking_assert (precision == op1.precision);
+
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < len; i++)
+    {
+      o0 = val[i];
+      o1 = op1.val[i];
+      x = o0 + o1 + carry;
+      result.val [i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+
+  /* Uncompress the rest.  */
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = val[i];
+      o1 = mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = mask0;
+      o1 = op1.val[i];
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 + mask1 + carry;
+      result.len++;
+      /* If we were short, we could not have overflowed.  */
+      goto ex;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (sgn == wide_int::SIGNED)
+	{
+	  if (((!(o0 ^ o1)) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
+	    *overflow = true;
+	}
+      else if (old_carry)
+	{
+	  if ((~o0) <= o1)
+	    *overflow = true;
+	}
+      else
+	{
+	  if ((~o0) < o1)
+	    *overflow = true;
+	}
+    }
+  else
+    {
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  If there are any non zero bits above the prec,
+	     we overflowed. */
+	  o0 = zext_hwi (o0, small_prec);
+	  o1 = zext_hwi (o1, small_prec);
+	  x = o0 + o1 + old_carry;
+	  if (x >> small_prec)
+	    *overflow = true;
+	}
+      else 
+	{
+	  /* Overflow in this case is easy since we can see bits beyond
+	     the precision.  If the value computed is not the sign
+	     extended value, then we have overflow.  */
+	  unsigned HOST_WIDE_INT y = sext_hwi (x, small_prec);
+	  if (x != y)
+	    *overflow = true;
+	}
+    }
+
+ ex:
+  result.canonize ();
+
+  return result;
+}
+
+/* Count leading zeros of THIS but only looking at the bits in the
+   smallest HWI of size mode.  */
+
+wide_int
+wide_int::clz (unsigned int prec) const
+{
+  return wide_int::from_shwi (clz (), prec);
+}
+
+/* Count leading zeros of THIS.  */
+
+int
+wide_int::clz () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+
+      return count;
+    }
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = clz_hwi (v) - (HOST_BITS_PER_WIDE_INT - small_prec);
+      start = len - 2;
+      if (v != 0)
+	{
+	  return count;
+	}
+    }
+  else
+    {
+      count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = elt (i);
+      count += clz_hwi (v);
+      if (v != 0)
+	break;
+    }
+
+  return count;
+}
+
+wide_int
+wide_int::clrsb (unsigned int prec) const
+{
+  return wide_int::from_shwi (clrsb (), prec);
+}
+
+/* Count the number of redundant leading bits of THIS.  Return result
+   as a HOST_WIDE_INT.  There is a wrapper to convert this into a
+   wide_int.  */
+
+int
+wide_int::clrsb () const
+{
+  if (neg_p ())
+    return operator ~ ().clz () - 1;
+
+  return clz () - 1;
+}
+
+wide_int
+wide_int::ctz (unsigned int prec) const
+{
+  return wide_int::from_shwi (ctz (), prec);
+}
+
+/* Count zeros of THIS.  Return result as a HOST_WIDE_INT.  There is a
+   wrapper to convert this into a wide_int.  */
+
+int
+wide_int::ctz () const
+{
+  int i;
+  unsigned int count = 0;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int end;
+  bool more_to_do;
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+
+      return count;
+    }
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      end = len - 1;
+      more_to_do = true;
+    }
+  else
+    {
+      end = len;
+      more_to_do = false;
+    }
+
+  for (i = 0; i < end; i++)
+    {
+      v = val[i];
+      count += ctz_hwi (v);
+      if (v != 0)
+	{
+	  return count;
+	}
+    }
+
+  if (more_to_do)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = ctz_hwi (v);
+      /* The top word was all zeros so we have to cut it back to prec,
+	 because we are counting some of the zeros above the
+	 interesting part.  */
+      if (count > precision)
+	count = precision;
+    }
+  else
+    /* Skip over the blocks that are not represented.  They must be
+       all zeros at this point.  */
+    count = precision;
+
+  return count;
+}
+
+/* ffs of THIS.  */
+
+wide_int
+wide_int::ffs () const
+{
+  HOST_WIDE_INT count = ctz ();
+  if (count == precision)
+    count = 0;
+  else
+    count += 1;
+
+  return wide_int::from_shwi (count, word_mode);
+}
+
+/* Subroutines of the multiplication and division operations.  Unpack
+   the first IN_LEN HOST_WIDE_INTs in INPUT into 2 * IN_LEN
+   HOST_HALF_WIDE_INTs of RESULT.  The rest of RESULT is filled by
+   uncompressing the top bit of INPUT[IN_LEN - 1].  */
+
+static void
+wi_unpack (unsigned HOST_HALF_WIDE_INT *result, 
+	   const unsigned HOST_WIDE_INT *input,
+	   int in_len, int out_len)
+{
+  int i;
+  int j = 0;
+  HOST_WIDE_INT mask;
+
+  for (i = 0; i <in_len; i++)
+    {
+      result[j++] = input[i];
+      result[j++] = input[i] >> HOST_BITS_PER_HALF_WIDE_INT;
+    }
+  mask = ((HOST_WIDE_INT)input[in_len - 1]) >> (HOST_BITS_PER_WIDE_INT - 1);
+  mask &= HALF_INT_MASK;
+
+  /* Smear the sign bit.  */
+  while (j < out_len)
+    result[j++] = mask;
+}
+
+/* The inverse of wi_unpack.  IN_LEN is the the number of input
+   blocks.  The number of output blocks will be half this amount.  */
+
+static void
+wi_pack (unsigned HOST_WIDE_INT *result, 
+	 const unsigned HOST_HALF_WIDE_INT *input, 
+	 int in_len)
+{
+  int i = 0;
+  int j = 0;
+
+  while (i < in_len - 2)
+    {
+      result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+	| ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+      i += 2;
+    }
+
+  /* Handle the case where in_len is odd.   For this we zero extend.  */
+  if (i & 1)
+    result[j++] = (unsigned HOST_WIDE_INT)input[i];
+  else
+    result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+      | ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+}
+
+/* Return an integer that is the exact log2 of THIS.  */
+
+int
+wide_int::exact_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  HOST_WIDE_INT count;
+  HOST_WIDE_INT result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec)
+	v = zext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = ::exact_log2 (v);
+      goto ex;
+    }
+
+  count = ctz ();
+  if (clz () + count + 1 == precision)
+    {
+      result = count;
+      goto ex;
+    }
+
+  result = -1;
+
+ ex:
+  return result;
+}
+
+/* Return an integer that is the floor log2 of THIS.  */
+
+int
+wide_int::floor_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  HOST_WIDE_INT result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec)
+	v = zext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = ::floor_log2 (v);
+      goto ex;
+    }
+
+  result = precision - 1 - clz ();
+
+ ex:
+  return result;
+}
+
+
+/* Multiply Op1 by Op2.  If HIGH is set, only the upper half of the
+   result is returned.  If FULL is set, the entire result is returned
+   in a mode that is twice the width of the inputs.  However, that
+   mode needs to exist if the value is to be usable.  Clients that use
+   FULL need to check for this.
+
+   If HIGH or FULL are not setm throw away the upper half after the check
+   is made to see if it overflows.  Unfortunately there is no better
+   way to check for overflow than to do this.  OVERFLOW is assumed to
+   be sticky so it should be initialized.  SGN controls the signess
+   and is used to check overflow or if HIGH or FULL is set.  */
+
+wide_int
+wide_int::mul_internal (bool high, bool full, 
+			const wide_int *op1, const wide_int *op2,
+			wide_int::SignOp sgn,  bool *overflow, 
+			bool needs_overflow)
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1, k, t;
+  unsigned int i;
+  unsigned int j;
+  unsigned int prec = op1->get_precision ();
+  unsigned int blocks_needed = BLOCKS_NEEDED (prec);
+  unsigned int half_blocks_needed = blocks_needed * 2;
+  /* The sizes here are scaled to support a 2x largest mode by 2x
+     largest mode yielding a 4x largest mode result.  This is what is
+     needed by vpn.  */
+
+  unsigned HOST_HALF_WIDE_INT 
+    u[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT 
+    v[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  /* The '2' in 'R' is because we are internally doing a full
+     multiply.  */
+  unsigned HOST_HALF_WIDE_INT 
+    r[2 * 2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1;
+
+  gcc_checking_assert (op1->precision == op2->precision);
+
+  /* If the top level routine did not really pass in an overflow, then
+     just make sure that we never attempt to set it.  */
+  if (overflow == 0)
+    needs_overflow = false;
+  result.precision = op1->precision;
+
+  if (high || full || needs_overflow)
+    {
+      /* If we need to check for overflow, we can only do half wide
+	 multiplies quickly because we need to look at the top bits to
+	 check for the overflow.  */
+      if (prec <= HOST_BITS_PER_HALF_WIDE_INT)
+	{
+	  HOST_WIDE_INT t, r;
+	  result.len = 1;
+	  o0 = op1->elt (0);
+	  o1 = op2->elt (0);
+	  r = o0 * o1;
+	  /* Signed shift down will leave 0 or -1 if there was no
+	     overflow for signed or 0 for unsigned.  */
+	  t = r >> (HOST_BITS_PER_HALF_WIDE_INT - 1);
+	  if (needs_overflow)
+	    {
+	      if (sgn == wide_int::SIGNED)
+		{
+		  if (t != (HOST_WIDE_INT)-1 && t != 0)
+		    *overflow = true;
+		}
+	      else
+		{
+		  if (t != 0)
+		    *overflow = true;
+		}
+	    }
+	  if (full)
+	    {
+	      result.val[0] = sext_hwi (r, prec * 2);
+	      result.precision = op1->precision * 2;
+	    }
+	  else if (high)
+	    result.val[0] = r >> prec;
+	  else
+	    result.val[0] = sext_hwi (r, prec);
+	  return result;
+	}
+    }
+
+  wi_unpack (u, (const unsigned HOST_WIDE_INT*)op1->val, op1->len,
+	     half_blocks_needed);
+  wi_unpack (v, (const unsigned HOST_WIDE_INT*)op2->val, op2->len,
+	     half_blocks_needed);
+
+  /* The 2 is for a full mult.  */
+  memset (r, 0, half_blocks_needed * 2 
+	  * HOST_BITS_PER_HALF_WIDE_INT / BITS_PER_UNIT);
+
+  for (j = 0; j < half_blocks_needed; j++)
+    {
+      k = 0;
+      for (i = 0; i < half_blocks_needed; i++)
+	{
+	  t = ((unsigned HOST_WIDE_INT)u[i] * (unsigned HOST_WIDE_INT)v[j]
+	       + r[i + j] + k);
+	  r[i + j] = t & HALF_INT_MASK;
+	  k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	}
+      r[j + half_blocks_needed] = k;
+    }
+
+  /* We did unsigned math above.  For signed we must adjust the
+     product (assuming we need to see that).  */
+  if (sgn == wide_int::SIGNED && (full || high || needs_overflow))
+    {
+      unsigned HOST_WIDE_INT b;
+      if ((*op1).neg_p ())
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)v[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+      if ((*op2).neg_p ())
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)u[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+    }
+
+  if (needs_overflow)
+    {
+      HOST_WIDE_INT top;
+
+      /* For unsigned, overflow is true if any of the top bits are set.
+	 For signed, overflow is true if any of the top bits are not equal
+	 to the sign bit.  */
+      if (sgn == wide_int::UNSIGNED)
+	top = 0;
+      else
+	{
+	  top = r[(half_blocks_needed) - 1];
+	  top = ((top << (HOST_BITS_PER_WIDE_INT / 2))
+		 >> (HOST_BITS_PER_WIDE_INT - 1));
+	  top &= mask;
+	}
+      
+      for (i = half_blocks_needed; i < half_blocks_needed * 2; i++)
+	if (((HOST_WIDE_INT)(r[i] & mask)) != top)
+	  *overflow = true; 
+    }
+
+  if (full)
+    {
+      /* compute [2prec] <- [prec] * [prec] */
+      wi_pack ((unsigned HOST_WIDE_INT*)result.val, r, 2 * half_blocks_needed);
+      result.len = blocks_needed * 2;
+      result.precision = op1->precision * 2;
+    }
+  else if (high)
+    {
+      /* compute [prec] <- ([prec] * [prec]) >> [prec] */
+      wi_pack ((unsigned HOST_WIDE_INT*)&result.val [blocks_needed >> 1],
+	       r, half_blocks_needed);
+      result.len = blocks_needed;
+    }
+  else
+    {
+      /* compute [prec] <- ([prec] * [prec]) && ((1 << [prec]) - 1) */
+      wi_pack ((unsigned HOST_WIDE_INT*)result.val, r, half_blocks_needed);
+      result.len = blocks_needed;
+    }
+      
+  result.canonize ();
+
+  return result;
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.
+   OVERFLOW is set true if the result overflows.  */
+
+wide_int 
+wide_int::mul (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  return mul_internal (false, false, this, &op1, sgn, overflow, true);
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.  The
+   result is twice the precision as the operands.  The signess is
+   specified with SGN.  */
+
+wide_int
+wide_int::mul_full (const wide_int &op1, SignOp sgn) const
+{
+  return mul_internal (false, true, this, &op1, sgn, 0, false);
+}
+
+/* Multiply THIS and OP1 and return the high part of that result.  The
+   signess is specified with SGN.  The result is the same precision as
+   the operands.  The mode is the same mode as the operands.  The
+   signess is specified with y.  */
+
+wide_int
+wide_int::mul_high (const wide_int &op1, SignOp sgn) const
+{
+  return mul_internal (true, false, this, &op1, sgn, 0, false);
+}
+
+/* Compute the parity of THIS.  */
+
+wide_int
+wide_int::parity (unsigned int prec) const
+{
+  int count = popcount ();
+  return wide_int::from_shwi (count & 1, prec);
+}
+
+/* Compute the population count of THIS producing a number with
+   PREC.  */
+
+wide_int
+wide_int::popcount (unsigned int prec) const
+{
+  return wide_int::from_shwi (popcount (), prec);
+}
+
+/* Compute the population count of THIS.  */
+
+int
+wide_int::popcount () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = popcount_hwi (v);
+      start = len - 2;
+    }
+  else
+    {
+      if (sign_mask ())
+	count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      else
+	count = 0;
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = val[i];
+      count += popcount_hwi (v);
+    }
+
+  return count;
+}
+
+/* Subtract of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::sub_large (const wide_int &op1) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the borrow in of the first element at 1.  */
+  unsigned HOST_WIDE_INT borrow = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1.len ? (unsigned HOST_WIDE_INT)op1.val[i] : mask1;
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      borrow = o0 < o1;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 - mask1 - borrow;
+      result.len++;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/* Subtract of THIS and OP1 with overflow checking.  If the result
+   overflows within the precision, set OVERFLOW.  OVERFLOW is assumed
+   to be sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::sub (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT borrow = 0;
+  unsigned HOST_WIDE_INT old_borrow = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int i, small_prec;
+
+  gcc_checking_assert (precision == op1.precision);
+
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < len; i++)
+    {
+      o0 = val[i];
+      o1 = op1.val[i];
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  /* Uncompress the rest.  */
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = val[i];
+      o1 = mask1;
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  for (i = op1.len; i < len; i++)
+    {
+      o0 = mask0;
+      o1 = op1.val[i];
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 - mask1 - borrow;
+      result.len++;
+      /* If we were short, we could not have overflowed.  */
+      goto ex;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (sgn == wide_int::SIGNED)
+	{
+	  if (((x ^ o0) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
+	    *overflow = true;
+	}
+      else if (old_borrow)
+	{
+	  if ((~o0) <= o1)
+	    *overflow = true;
+	}
+      else
+	{
+	  if ((~o0) < o1)
+	    *overflow = true;
+	}
+    }
+  else
+    {
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  If there are any non zero bits above the prec,
+	     we overflowed. */
+	  o0 = zext_hwi (o0, small_prec);
+	  o1 = zext_hwi (o1, small_prec);
+	  x = o0 - o1 - old_borrow;
+	  if (x >> small_prec)
+	    *overflow = true;
+	}
+      else 
+	{
+	  /* Overflow in this case is easy since we can see bits beyond
+	     the precision.  If the value computed is not the sign
+	     extended value, then we have overflow.  */
+	  unsigned HOST_WIDE_INT y = sext_hwi (x, small_prec);
+	  if (x != y)
+	    *overflow = true;
+	}
+    }
+
+ ex:
+  result.canonize ();
+
+  return result;
+}
+
+/*
+ * Division and Mod
+ */
+
+/* Compute B_QUOTIENT and B_REMAINDER from B_DIVIDEND/B_DIVISOR.  The
+   algorithm is a small modification of the algorithm in Hacker's
+   Delight by Warren, which itself is a small modification of Knuth's
+   algorithm.  M is the number of significant elements of U however
+   there needs to be at least one extra element of B_DIVIDEND
+   allocated, N is the number of elements of B_DIVISOR.  */
+
+void
+wide_int::divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+			     unsigned HOST_HALF_WIDE_INT *b_remainder,
+			     unsigned HOST_HALF_WIDE_INT *b_dividend, 
+			     unsigned HOST_HALF_WIDE_INT *b_divisor, 
+			     int m, int n)
+{
+  /* The "digits" are a HOST_HALF_WIDE_INT which the size of half of a
+     HOST_WIDE_INT and stored in the lower bits of each word.  This
+     algorithm should work properly on both 32 and 64 bit
+     machines.  */
+  unsigned HOST_WIDE_INT b
+    = (unsigned HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT;
+  unsigned HOST_WIDE_INT qhat;   /* Estimate of quotient digit.  */
+  unsigned HOST_WIDE_INT rhat;   /* A remainder.  */
+  unsigned HOST_WIDE_INT p;      /* Product of two digits.  */
+  HOST_WIDE_INT s, i, j, t, k;
+
+  /* Single digit divisor.  */
+  if (n == 1)
+    {
+      k = 0;
+      for (j = m - 1; j >= 0; j--)
+	{
+	  b_quotient[j] = (k * b + b_dividend[j])/b_divisor[0];
+	  k = ((k * b + b_dividend[j])
+	       - ((unsigned HOST_WIDE_INT)b_quotient[j]
+		  * (unsigned HOST_WIDE_INT)b_divisor[0]));
+	}
+      b_remainder[0] = k;
+      return;
+    }
+
+  s = clz_hwi (b_divisor[n-1]) - HOST_BITS_PER_HALF_WIDE_INT; /* CHECK clz */
+
+  /* Normalize B_DIVIDEND and B_DIVISOR.  Unlike the published
+     algorithm, we can overwrite b_dividend and b_divisor, so we do
+     that.  */
+  for (i = n - 1; i > 0; i--)
+    b_divisor[i] = (b_divisor[i] << s)
+      | (b_divisor[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_divisor[0] = b_divisor[0] << s;
+
+  b_dividend[m] = b_dividend[m-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s);
+  for (i = m - 1; i > 0; i--)
+    b_dividend[i] = (b_dividend[i] << s)
+      | (b_dividend[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_dividend[0] = b_dividend[0] << s;
+
+  /* Main loop.  */
+  for (j = m - n; j >= 0; j--)
+    {
+      qhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) / b_divisor[n-1];
+      rhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) - qhat * b_divisor[n-1];
+    again:
+      if (qhat >= b || qhat * b_divisor[n-2] > b * rhat + b_dividend[j+n-2])
+	{
+	  qhat -= 1;
+	  rhat += b_divisor[n-1];
+	  if (rhat < b)
+	    goto again;
+	}
+
+      /* Multiply and subtract.  */
+      k = 0;
+      for (i = 0; i < n; i++)
+	{
+	  p = qhat * b_divisor[i];
+	  t = b_dividend[i+j] - k - (p & HALF_INT_MASK);
+	  b_dividend[i + j] = t;
+	  k = ((p >> HOST_BITS_PER_HALF_WIDE_INT)
+	       - (t >> HOST_BITS_PER_HALF_WIDE_INT));
+	}
+      t = b_dividend[j+n] - k;
+      b_dividend[j+n] = t;
+
+      b_quotient[j] = qhat;
+      if (t < 0)
+	{
+	  b_quotient[j] -= 1;
+	  k = 0;
+	  for (i = 0; i < n; i++)
+	    {
+	      t = (HOST_WIDE_INT)b_dividend[i+j] + b_divisor[i] + k;
+	      b_dividend[i+j] = t;
+	      k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	    }
+	  b_dividend[j+n] += k;
+	}
+    }
+  for (i = 0; i < n; i++)
+    b_remainder[i] = (b_dividend[i] >> s) 
+      | (b_dividend[i+1] << (HOST_BITS_PER_HALF_WIDE_INT - s));
+}
+
+
+/* Do a truncating divide DIVISOR into DIVIDEND.  The result is the
+   same size as the operands.  SIGN is either wide_int::SIGNED or
+   wide_int::UNSIGNED.  */
+
+wide_int
+wide_int::divmod_internal (bool compute_quotient, 
+			   const wide_int *dividend, const wide_int *divisor,
+			   wide_int::SignOp sgn, wide_int *remainder,
+			   bool compute_remainder, 
+			   bool *oflow)
+{
+  wide_int quotient, u0, u1;
+  unsigned int prec = dividend->get_precision();
+  int blocks_needed = 2 * BLOCKS_NEEDED (prec);
+  /* The '2' in the next 4 vars are because they are built on half
+     sized wide ints.  */
+  unsigned HOST_HALF_WIDE_INT 
+    b_quotient[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_remainder[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_dividend[(MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT) + 1];
+  unsigned HOST_HALF_WIDE_INT
+    b_divisor[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  int m, n;
+  bool dividend_neg = false;
+  bool divisor_neg = false;
+  bool overflow = false;
+
+  gcc_checking_assert (dividend->precision == divisor->precision);
+
+  if ((*divisor).zero_p ())
+    overflow = true;
+
+  /* The smallest signed number / -1 causes overflow.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      wide_int t = wide_int::set_bit_in_zero (prec - 1, prec);
+      if (*dividend == t && (*divisor).minus_one_p ())
+	overflow = true;
+    }
+
+  quotient.precision = prec;
+  remainder->precision = prec;
+
+  /* If overflow is set, just get out.  There will only be grief by
+     continuing.  */
+  if (overflow)
+    {
+      if (compute_remainder)
+	{
+	  remainder->len = 1;
+	  remainder->val[0] = 0;
+	}
+      if (oflow != 0)
+	*oflow = true;
+      return wide_int::zero (prec);
+    }
+
+  /* Do it on the host if you can.  */
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      quotient.len = 1;
+      remainder->len = 1;
+      if (sgn == wide_int::SIGNED)
+	{
+	  quotient.val[0] 
+	    = sext_hwi (dividend->elt (0) / divisor->val[0], prec);
+	  remainder->val[0] 
+	    = sext_hwi (dividend->elt (0) % divisor->val[0], prec);
+	}
+      else
+	{
+	  unsigned HOST_WIDE_INT o0 = dividend->elt (0);
+	  unsigned HOST_WIDE_INT o1 = divisor->elt (0);
+
+	  if (prec < HOST_BITS_PER_WIDE_INT)
+	    {
+	      o0 = zext_hwi (o0, prec);
+	      o1 = zext_hwi (o1, prec);
+	    }
+	  quotient.val[0] = sext_hwi (o0 / o1, prec);
+	  remainder->val[0] = sext_hwi (o0 % o1, prec);
+	}
+
+      return quotient;
+    }
+
+  /* Make the divisor and divident positive and remember what we
+     did.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      if (dividend->sign_mask ())
+	{
+	  u0 = dividend->neg ();
+	  dividend = &u0;
+	  dividend_neg = true;
+	}
+      if (divisor->sign_mask ())
+	{
+	  u1 = divisor->neg ();
+	  divisor = &u1;
+	  divisor_neg = true;
+	}
+    }
+
+  wi_unpack (b_dividend, (const unsigned HOST_WIDE_INT*)dividend->val,
+	     dividend->len, blocks_needed);
+  wi_unpack (b_divisor, (const unsigned HOST_WIDE_INT*)divisor->val, 
+	     divisor->len, blocks_needed);
+
+  if (dividend->sign_mask ())
+    m = blocks_needed;
+  else
+    m = 2 * dividend->get_len ();
+
+  if (divisor->sign_mask ())
+    n = blocks_needed;
+  else
+    n = 2 * divisor->get_len ();
+
+  /* It is known that the top input block to the divisor is non zero,
+     but when this block is split into two half blocks, it may be that
+     the top half block is zero.  Skip over this half block.  */
+  if (b_divisor[n - 1] == 0)
+    n--;
+
+  divmod_internal_2 (b_quotient, b_remainder, b_dividend, b_divisor, m, n);
+
+  if (compute_quotient)
+    {
+      wi_pack ((unsigned HOST_WIDE_INT*)quotient.val, b_quotient, m);
+      quotient.len = m / 2;
+      quotient.canonize ();
+      /* The quotient is neg if exactly one of the divisor or dividend is
+	 neg.  */
+      if (dividend_neg != divisor_neg)
+	quotient = quotient.neg ();
+    }
+  else
+    quotient = wide_int::zero (word_mode);
+
+  if (compute_remainder)
+    {
+      wi_pack ((unsigned HOST_WIDE_INT*)remainder->val, b_remainder, n);
+      if (n & 1)
+	n++;
+      remainder->len = n / 2;
+      (*remainder).canonize ();
+      /* The remainder is always the same sign as the dividend.  */
+      if (dividend_neg)
+	*remainder = (*remainder).neg ();
+    }
+  else
+    *remainder = wide_int::zero (word_mode);
+
+  return quotient;
+}
+
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is truncated.
+   Overflow is set to true if the result overflows, otherwise it is
+   not set.  */
+wide_int
+wide_int::div_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  
+  return divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, false, overflow);
+}
+
+/* Divide DIVISOR into THIS producing both the quotient and remainder.
+   The result is the same size as the operands.  The sign is specified
+   in SGN.  The output is truncated.  */
+
+wide_int
+wide_int::divmod_trunc (const wide_int &divisor, wide_int *remainder, SignOp sgn) const
+{
+  bool overflow = false;
+
+  return divmod_internal (true, this, &divisor, sgn, 
+			  remainder, true, &overflow);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_trunc (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+
+  divmod_internal (true, this, &divisor, sgn, 
+			  &remainder, true, overflow);
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is floor
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return quotient - wide_int::one (precision);
+  return quotient;
+}
+
+
+/* Divide DIVISOR into THIS.  The remainder is also produced in
+   REMAINDER.  The result is the same size as the operands.  The sign
+   is specified in SGN.  The output is floor truncated.  Overflow is
+   set to true if the result overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::divmod_floor (const wide_int &divisor, wide_int *remainder, SignOp sgn) const
+{
+  wide_int quotient;
+  bool overflow = false;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      remainder, true, &overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !(*remainder).zero_p ())
+    {
+      *remainder = *remainder - divisor;
+      return quotient - wide_int::one (precision);
+    }
+  return quotient;
+}
+
+
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is floor truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_floor (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return remainder - divisor;
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is ceil
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return quotient;
+      else
+	return quotient + wide_int::one (precision);
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is the
+   same size as the operands.  The sign is specified in SGN.  The
+   output is ceil truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_ceil (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return remainder;
+      else
+	return remainder - divisor;
+    }
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is round
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+wide_int
+wide_int::div_round (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+  if (!remainder.zero_p ())
+    {
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu_large (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return quotient - wide_int::one (precision);
+	      else 
+		return quotient + wide_int::one (precision);
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu_large (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return quotient + wide_int::one (precision);
+	}
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is round truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+wide_int
+wide_int::mod_round (const wide_int &divisor, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+
+  quotient = divmod_internal (true, this, &divisor, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu_large (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return remainder + divisor;
+	      else 
+		return remainder - divisor;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu_large (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return remainder - divisor;
+	}
+    }
+  return remainder;
+}
+
+/*
+ * Shifting, rotating and extraction.
+ */
+
+/* Extract WIDTH bits from THIS starting at OFFSET.  The result is
+   assumed to fit in a HOST_WIDE_INT.  This function is safe in that
+   it can properly access elements that may not be explicitly
+   represented.  */
+
+HOST_WIDE_INT
+wide_int::extract_to_hwi (int offset, int width) const
+{
+  int start_elt, end_elt, shift;
+  HOST_WIDE_INT x;
+
+  /* Get rid of the easy cases first.   */
+  if (offset >= len * HOST_BITS_PER_WIDE_INT)
+    return sign_mask ();
+  if (offset + width <= 0)
+    return 0;
+
+  shift = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset < 0)
+    {
+      start_elt = -1;
+      end_elt = 0;
+      x = 0;
+    }
+  else
+    {
+      start_elt = offset / HOST_BITS_PER_WIDE_INT;
+      end_elt = (offset + width - 1) / HOST_BITS_PER_WIDE_INT;
+      x = start_elt >= len 
+	? sign_mask ()
+	: (unsigned HOST_WIDE_INT)val[start_elt] >> shift;
+    }
+
+  if (start_elt != end_elt)
+    {
+      HOST_WIDE_INT y = end_elt == len
+	? sign_mask () : val[end_elt];
+
+      x |= y << (HOST_BITS_PER_WIDE_INT - shift);
+    }
+
+  if (width != HOST_BITS_PER_WIDE_INT)
+    x &= ((HOST_WIDE_INT)1 << width) - 1;
+
+  return x;
+}
+
+
+/* Left shift THIS by CNT.  See the definition of Op.TRUNC for how to
+   set Z.  Since this is used internally, it has the ability to
+   specify the BISIZE and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+wide_int
+wide_int::lshift_large (unsigned int cnt, unsigned int res_prec) const
+{
+  wide_int result;
+  unsigned int i;
+
+  result.precision = res_prec;
+
+  if (cnt >= res_prec)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+      return result;
+    }
+
+  for (i = 0; i < res_prec; i += HOST_BITS_PER_WIDE_INT)
+    result.val[i / HOST_BITS_PER_WIDE_INT]
+      = extract_to_hwi (i - cnt, HOST_BITS_PER_WIDE_INT);
+
+  result.len = BLOCKS_NEEDED (res_prec);
+  result.canonize ();
+
+  return result;
+}
+
+/* Rotate THIS left by CNT within its precision.  */
+
+wide_int
+wide_int::lrotate (unsigned int cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (cnt, NONE);
+  right = rshiftu (precision - cnt, NONE);
+  result = left | right;
+
+  return result;
+}
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set Z.  */
+
+wide_int
+wide_int::rshiftu_large (unsigned int cnt) const
+{
+  wide_int result;
+  int stop_block, offset, i;
+
+  result.precision = precision;
+
+  if (cnt >= precision)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  offset = (precision - cnt) & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset)
+    result.val[stop_block - 1] = zext_hwi (result.val[stop_block - 1], offset);
+  else
+    /* The top block had a 1 at the top position so it will decompress
+       wrong unless a zero block is added.  This only works because we
+       know the shift was greater than 0.  */
+    if (result.val[stop_block - 1] < 0)
+      result.val[result.len++] = 0;
+  return result;
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set Z.  */
+
+wide_int
+wide_int::rshifts_large (unsigned int cnt) const
+{
+  wide_int result;
+  int stop_block, i;
+
+  result.precision = precision;
+
+  if (cnt >= precision)
+    {
+      HOST_WIDE_INT m = sign_mask ();
+      result.val[0] = m;
+      result.len = 1;
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  /* No need to sign extend the last block, since it extract_to_hwi
+     already did that.  */
+  return result;
+}
+
+/* Rotate THIS right by CNT within its precision.  */
+
+wide_int
+wide_int::rrotate (unsigned int cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (precision - cnt, NONE);
+  right = rshiftu (cnt, NONE);
+  result = left | right;
+
+  return result;
+}
+
+/*
+ * Private utilities.
+ */
+/* Decompress THIS for at least TARGET bits into a result with
+   precision PREC.  */
+
+wide_int
+wide_int::decompress (unsigned int target, unsigned int prec) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (target);
+  HOST_WIDE_INT mask;
+  int len, i;
+
+  result.precision = prec;
+  result.len = blocks_needed;
+
+  for (i = 0; i < this->len; i++)
+    result.val[i] = val[i];
+
+  len = this->len;
+
+  if (target > result.precision)
+    return result;
+
+  /* The extension that we are doing here is not sign extension, it is
+     decompression.  */
+  mask = sign_mask ();
+  while (len < blocks_needed)
+    result.val[len++] = mask;
+
+  return result;
+}
+
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
new file mode 100644
index 0000000..bec42f5
--- /dev/null
+++ b/gcc/wide-int.h
@@ -0,0 +1,1939 @@
+/* Operations with very long integers.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef WIDE_INT_H
+#define WIDE_INT_H
+
+/* A wide integer is currently represented as a vector of
+   HOST_WIDE_INTs.  The vector contains enough elements to hold a
+   value of MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT which is
+   a derived for each host target combination.  The values are stored
+   in the vector with the least signicant HOST_BITS_PER_WIDE_INT bits
+   of the value stored in element 0.
+
+   A wide_int contains three fields: the vector (VAL), precision and a
+   length, (LEN).  The length is the number of HWIs needed to
+   represent the value.
+
+   Since most integers used in a compiler are small values, it is
+   generally profitable to use a representation of the value that is
+   shorter than the modes precision.  LEN is used to indicate the
+   number of elements of the vector that are in use.  When LEN *
+   HOST_BITS_PER_WIDE_INT < the precision, the value has been
+   compressed.  The values of the elements of the vector greater than
+   LEN - 1. are all equal to the highest order bit of LEN.
+
+   The representation does not contain any information about
+   signedness of the represented value, so it can be used to represent
+   both signed and unsigned numbers.  For operations where the results
+   depend on signedness (division, comparisons), the signedness must
+   be specified separately.  For operations where the signness
+   matters, one of the operands to the operation specifies either
+   wide_int::SIGNED or wide_int::UNSIGNED.
+
+   All constructors for wide_int take either a precision, an enum
+   machine_mode or tree_type.  */
+
+
+#ifndef GENERATOR_FILE
+#include "tree.h"
+#include "system.h"
+#include "hwint.h"
+#include "options.h"
+#include "tm.h"
+#include "insn-modes.h"
+#include "machmode.h"
+#include "double-int.h"
+#include <gmp.h>
+#include "dumpfile.h"
+#include "real.h"
+
+
+class wide_int {
+  /* Internal representation.  */
+  
+  /* VAL is set to a size that is capable of computing a full
+     multiplication on the largest mode that is represented on the
+     target.  The full multiplication is use by tree-vrp.  tree-vpn
+     currently does a 2x largest mode by 2x largest mode yielding a 4x
+     largest mode result.  If operations are added that require larger
+     buffers, then VAL needs to be changed.  */
+  HOST_WIDE_INT val[(4 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1)
+		    / HOST_BITS_PER_WIDE_INT];
+  unsigned short len;
+  unsigned int precision;
+
+ public:
+  enum ShiftOp {
+    NONE,
+    /* There are two uses for the wide-int shifting functions.  The
+       first use is as an emulation of the target hardware.  The
+       second use is as service routines for other optimizations.  The
+       first case needs to be identified by passing TRUNC as the value
+       of ShiftOp so that shift amount is properly handled according to the
+       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
+       amount is always truncated by the bytesize of the mode of
+       THIS.  */
+    TRUNC
+  };
+
+  enum SignOp {
+    /* Many of the math functions produce different results depending
+       on if they are SIGNED or UNSIGNED.  In general, there are two
+       different functions, whose names are prefixed with an 'S" and
+       or an 'U'.  However, for some math functions there is also a
+       routine that does not have the prefix and takes an SignOp
+       parameter of SIGNED or UNSIGNED.  */
+    SIGNED,
+    UNSIGNED
+  };
+
+  /* Conversions.  */
+
+  static wide_int from_shwi (HOST_WIDE_INT op0, 
+			     unsigned int precision, bool *overflow = 0);
+  static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+			     unsigned int precision, bool *overflow = 0);
+
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type, 
+				   bool *overflow = 0);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+				    bool *overflow = 0);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+				    enum machine_mode mode, 
+				    bool *overflow = 0);
+  static wide_int from_array (const HOST_WIDE_INT* op0,
+			      unsigned int len, 
+			      unsigned int precision); 
+  inline static wide_int from_array (const HOST_WIDE_INT* op0,
+				     unsigned int len,
+				     enum machine_mode mode);
+  inline static wide_int from_array (const HOST_WIDE_INT* op0,
+				     unsigned int len,
+				     const_tree type);
+
+  static wide_int from_double_int (double_int, 
+				   unsigned int precision);
+  inline static wide_int from_double_int (double_int, enum machine_mode);
+  static wide_int from_tree (const_tree);
+  static wide_int from_rtx (const_rtx, enum machine_mode);
+  static wide_int from_buffer (const unsigned char*, int);
+
+  inline HOST_WIDE_INT to_shwi () const;
+  inline HOST_WIDE_INT to_shwi (unsigned int prec) const;
+  inline unsigned HOST_WIDE_INT to_uhwi () const;
+  inline unsigned HOST_WIDE_INT to_uhwi (unsigned int prec) const;
+
+  /* Largest and smallest values that are represented in modes or precisions.  */
+
+  static wide_int max_value (unsigned int prec, 
+			     unsigned int precision, SignOp sgn);
+  inline static wide_int max_value (unsigned int precision, SignOp sgn);
+  inline static wide_int max_value (const_tree type);
+  inline static wide_int max_value (enum machine_mode mode, SignOp sgn);
+  
+  static wide_int min_value (unsigned int prec, 
+			     unsigned int precision, SignOp sgn);
+  inline static wide_int min_value (unsigned int precision, SignOp sgn);
+  inline static wide_int min_value (const_tree type);
+  inline static wide_int min_value (enum machine_mode mode, SignOp sgn);
+  
+  /* Small constants */
+
+  inline static wide_int minus_one (unsigned int prec);
+  inline static wide_int zero (unsigned int prec);
+  inline static wide_int one (unsigned int prec);
+  inline static wide_int two (unsigned int prec);
+
+  /* Accessors.  */
+
+  inline unsigned short get_len () const;
+  inline unsigned int get_precision () const;
+  inline HOST_WIDE_INT elt (unsigned int i) const;
+
+  /* Printing functions.  */
+
+  void print_dec (char *buf, SignOp sgn) const;
+  void print_dec (FILE *file, SignOp sgn) const;
+  void print_decs (char *buf) const;
+  void print_decs (FILE *file) const;
+  void print_decu (char *buf) const;
+  void print_decu (FILE *file) const;
+  void print_hex (char *buf) const;
+  void print_hex (FILE *file) const;
+
+  /* Comparative functions.  */
+
+  inline bool minus_one_p () const;
+  inline bool zero_p () const;
+  inline bool one_p () const;
+  inline bool neg_p () const;
+
+  inline bool operator == (const wide_int &y) const;
+  inline bool operator != (const wide_int &y) const;
+  inline bool gt_p (HOST_WIDE_INT x, SignOp sgn) const;
+  inline bool gt_p (const wide_int &x, SignOp sgn) const;
+  inline bool gts_p (HOST_WIDE_INT y) const;
+  inline bool gts_p (const wide_int &y) const;
+  inline bool gtu_p (unsigned HOST_WIDE_INT y) const;
+  inline bool gtu_p (const wide_int &y) const;
+
+  inline bool lt_p (const HOST_WIDE_INT x, SignOp sgn) const;
+  inline bool lt_p (const wide_int &x, SignOp sgn) const;
+  inline bool lts_p (HOST_WIDE_INT y) const;
+  inline bool lts_p (const wide_int &y) const;
+  inline bool ltu_p (unsigned HOST_WIDE_INT y) const;
+  inline bool ltu_p (const wide_int &y) const;
+  inline int cmp (const wide_int &y, SignOp sgn) const;
+  inline int cmps (const wide_int &y) const;
+  inline int cmpu (const wide_int &y) const;
+
+  bool only_sign_bit_p (unsigned int prec) const;
+  inline bool only_sign_bit_p () const;
+  inline bool fits_uhwi_p () const;
+  inline bool fits_shwi_p () const;
+  bool fits_to_tree_p (const_tree type) const;
+  bool fits_u_p (unsigned int prec) const;
+  bool fits_s_p (unsigned int prec) const;
+
+  /* Min and max */
+
+  inline wide_int min (const wide_int &op1, SignOp sgn) const;
+  inline wide_int max (const wide_int &op1, SignOp sgn) const;
+  inline wide_int smin (const wide_int &op1) const;
+  inline wide_int smax (const wide_int &op1) const;
+  inline wide_int umin (const wide_int &op1) const;
+  inline wide_int umax (const wide_int &op1) const;
+
+  /* Extension, these do not change the precision.  */
+
+  inline wide_int ext (unsigned int offset, SignOp sgn) const;
+  wide_int sext (unsigned int offset) const;
+  wide_int zext (unsigned int offset) const;
+
+  /* Make a fast copy.  */
+
+  wide_int copy () const;
+
+  /* These change the underlying precision.  */
+  
+  wide_int force_to_size (unsigned int precision, SignOp sgn) const;
+  inline wide_int force_to_size (enum machine_mode mode, SignOp sgn) const;
+  inline wide_int force_to_size (const_tree type) const;
+  inline wide_int force_to_size (const_tree type, SignOp sgn) const;
+
+  inline wide_int sforce_to_size (enum machine_mode mode) const;
+  inline wide_int sforce_to_size (const_tree type) const;
+  inline wide_int zforce_to_size (enum machine_mode mode) const;
+  inline wide_int zforce_to_size (const_tree type) const;
+
+  /* Masking, and Insertion  */
+
+  wide_int set_bit (unsigned int bitpos) const;
+  static wide_int set_bit_in_zero (unsigned int bitpos, unsigned int prec);
+  inline static wide_int set_bit_in_zero (unsigned int, 
+					  enum machine_mode mode);
+  inline static wide_int set_bit_in_zero (unsigned int, const_tree type);
+  wide_int insert (const wide_int &op0, unsigned int offset,
+		   unsigned int width) const;
+  static wide_int mask (unsigned int start, bool negate, 
+			unsigned int prec);
+  inline static wide_int mask (unsigned int start, bool negate, 
+			       enum machine_mode mode);
+  inline static wide_int mask (unsigned int start, bool negate,
+			       const_tree type);
+  wide_int bswap () const;
+  static wide_int shifted_mask (unsigned int start, unsigned int width,
+				bool negate, unsigned int prec);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, enum machine_mode mode);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, const_tree type);
+  inline HOST_WIDE_INT sign_mask () const;
+
+  /* Logicals */
+
+  inline wide_int operator & (const wide_int &y) const;
+  inline wide_int and_not (const wide_int &y) const;
+  inline wide_int operator ~ () const;
+  inline wide_int operator | (const wide_int &y) const;
+  inline wide_int or_not (const wide_int &y) const;
+  inline wide_int operator ^ (const wide_int &y) const;
+
+  /* Arithmetic operation functions, alpha sorted.  */
+
+  wide_int abs () const;
+  inline wide_int operator + (const wide_int &y) const;
+  wide_int add (const wide_int &x, SignOp sgn, bool *overflow) const;
+  wide_int clz (unsigned int prec) const;
+  int clz () const;
+  wide_int clrsb (unsigned int prec) const;
+  int clrsb () const;
+  wide_int ctz (unsigned int prec) const;
+  int ctz () const;
+  int exact_log2 () const;
+  int floor_log2 () const;
+  wide_int ffs () const;
+  inline wide_int operator * (const wide_int &y) const;
+  wide_int mul (const wide_int &x, SignOp sgn, bool *overflow) const;
+  inline wide_int smul (const wide_int &x, bool *overflow) const;
+  inline wide_int umul (const wide_int &x, bool *overflow) const;
+  wide_int mul_full (const wide_int &x, SignOp sgn) const;
+  inline wide_int umul_full (const wide_int &x) const;
+  inline wide_int smul_full (const wide_int &x) const;
+  wide_int mul_high (const wide_int &x, SignOp sgn) const;
+  inline wide_int neg () const;
+  inline wide_int neg (bool *overflow) const;
+  wide_int parity (unsigned int prec) const;
+  int popcount () const;
+  wide_int popcount (unsigned int prec) const;
+  inline wide_int operator - (const wide_int &y) const;
+  wide_int sub (const wide_int &x, SignOp sgn, bool *overflow) const;
+
+  /* Divison and mod.  These are the ones that are actually used, but
+     there are a lot of them.  */
+
+  wide_int div_trunc (const wide_int &divisor, SignOp sgn, bool *overflow = 0) const;
+  inline wide_int sdiv_trunc (const wide_int &divisor) const;
+  inline wide_int udiv_trunc (const wide_int &divisor) const;
+
+  wide_int div_floor (const wide_int &divisor, SignOp sgn, bool *overflow = 0) const;
+  inline wide_int udiv_floor (const wide_int &divisor) const;
+  inline wide_int sdiv_floor (const wide_int &divisor) const;
+  wide_int div_ceil (const wide_int &divisor, SignOp sgn, bool *overflow = 0) const;
+  wide_int div_round (const wide_int &divisor, SignOp sgn, bool *overflow = 0) const;
+
+  wide_int divmod_trunc (const wide_int &divisor, wide_int *mod, SignOp sgn) const;
+  inline wide_int sdivmod_trunc (const wide_int &divisor, wide_int *mod) const;
+  inline wide_int udivmod_trunc (const wide_int &divisor, wide_int *mod) const;
+
+  wide_int divmod_floor (const wide_int &divisor, wide_int *mod, SignOp sgn) const;
+  inline wide_int sdivmod_floor (const wide_int &divisor, wide_int *mod) const;
+
+  wide_int mod_trunc (const wide_int &divisor, SignOp sgn, bool *overflow = 0) const;
+  inline wide_int smod_trunc (const wide_int &divisor) const;
+  inline wide_int umod_trunc (const wide_int &divisor) const;
+
+  wide_int mod_floor (const wide_int &divisor, SignOp sgn, bool *overflow = 0) const;
+  inline wide_int umod_floor (const wide_int &divisor) const;
+  wide_int mod_ceil (const wide_int &divisor, SignOp sgn, bool *overflow = 0) const;
+  wide_int mod_round (const wide_int &divisor, SignOp sgn, bool *overflow = 0) const;
+
+  /* Shifting rotating and extracting.  */
+  HOST_WIDE_INT extract_to_hwi (int offset, int width) const;
+
+  inline wide_int lshift (const wide_int &y, unsigned int bitsize,
+			  ShiftOp z = NONE) const;
+  inline wide_int lshift (unsigned int y, unsigned int precision, 
+			  unsigned int bitsize, ShiftOp z = NONE) const;
+  inline wide_int lshift (unsigned int y, unsigned int bitsize,
+			  ShiftOp z = NONE) const;
+
+  inline wide_int lrotate (const wide_int &y) const;
+  wide_int lrotate (unsigned int y) const;
+
+  inline wide_int rshift (const wide_int &y, SignOp sgn, unsigned int bitsize,
+			  ShiftOp z = NONE) const;
+  inline wide_int rshiftu (const wide_int &y, unsigned int bitsize,
+			   ShiftOp z = NONE) const;
+  inline wide_int rshiftu (unsigned int y, unsigned int bitsize,
+			   ShiftOp z = NONE) const;
+  inline wide_int rshifts (const wide_int &y, unsigned int bitsize,
+			   ShiftOp z = NONE) const;
+  inline wide_int rshifts (unsigned int y, unsigned int bitsize,
+			   ShiftOp z = NONE) const;
+
+  inline wide_int rrotate (const wide_int &y) const;
+  wide_int rrotate (unsigned int y) const;
+
+  static const int DUMP_MAX = (2 * (MAX_BITSIZE_MODE_ANY_INT / 4
+			       + MAX_BITSIZE_MODE_ANY_INT 
+				    / HOST_BITS_PER_WIDE_INT + 32));
+  char *dump (char* buf) const;
+ private:
+
+  /* 
+   * Internal versions that do the work if the values do not fit in a
+   * HWI.
+   */ 
+
+  /* Comparisons */
+  bool eq_p_large (const wide_int &op1) const;
+  bool lts_p_large (const wide_int &op1) const;
+  int cmps_large (const wide_int &op1) const;
+  bool ltu_p_large (const wide_int &op1) const;
+  int cmpu_large (const wide_int &op1) const;
+
+  /* Logicals.  */
+  wide_int and_large (const wide_int &op1) const;
+  wide_int and_not_large (const wide_int &y) const;
+  wide_int or_large (const wide_int &y) const;
+  wide_int or_not_large (const wide_int &y) const;
+  wide_int xor_large (const wide_int &y) const;
+
+  /* Arithmetic */
+  wide_int add_large (const wide_int &op1) const;
+  wide_int sub_large (const wide_int &op1) const;
+
+  wide_int lshift_large (unsigned int cnt, unsigned int res_prec) const;
+  wide_int rshiftu_large (unsigned int cnt) const;
+  wide_int rshifts_large (unsigned int cnt) const;
+
+  static wide_int
+    mul_internal (bool high, bool full, 
+		  const wide_int *op1, const wide_int *op2,
+		  wide_int::SignOp sgn,  bool *overflow, bool needs_overflow);
+  static void
+    divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+		       unsigned HOST_HALF_WIDE_INT *b_remainder,
+		       unsigned HOST_HALF_WIDE_INT *b_dividend, 
+		       unsigned HOST_HALF_WIDE_INT *b_divisor, 
+		       int m, int n);
+  static wide_int
+    divmod_internal (bool compute_quotient, 
+		     const wide_int *dividend, const wide_int *divisor,
+		     wide_int::SignOp sgn, wide_int *remainder,
+		     bool compute_remainder, 
+		     bool *overflow);
+
+
+  /* Private utility routines.  */
+  wide_int decompress (unsigned int target, unsigned int precision) const;
+  void canonize ();
+  static inline int trunc_shift (int cnt, unsigned int bitsize);
+  static inline int trunc_shift (const wide_int &cnt, 
+				 unsigned int bitsize, ShiftOp z);
+};
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with precision
+   taken from MODE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, enum machine_mode mode)
+{
+  return wide_int::set_bit_in_zero (bitpos, GET_MODE_PRECISION (mode));
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with precision
+   taken from TYPE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, const_tree type)
+{
+
+  return wide_int::set_bit_in_zero (bitpos, TYPE_PRECISION (type));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with precision
+   taken from MODE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, enum machine_mode mode)
+{
+  return wide_int::mask (width, negate, GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with precision
+   taken from TYPE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, const_tree type)
+{
+
+  return wide_int::mask (width, negate, TYPE_PRECISION (type));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the bits
+   above that up to the precision are zeros.  The result is inverted
+   if NEGATE is true.  The result is made with precision taken from
+   MODE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, enum machine_mode mode)
+{
+  return wide_int::shifted_mask (start, width, negate,
+				 GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the bits
+   above that up to the precision are zeros.  The result is inverted
+   if NEGATE is true.  The result is made with precision taken from
+   TYPE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, const_tree type)
+{
+
+  return wide_int::shifted_mask (start, width, negate,
+				 TYPE_PRECISION (type));
+}
+
+/* Produce 0 or -1 that is the smear of the sign bit.  */
+
+HOST_WIDE_INT
+wide_int::sign_mask () const
+{
+  int i = len - 1;
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
+	    >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* VRP appears to be badly broken and this is a very ugly fix.  */
+  if (i >= 0)
+    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
+
+  gcc_unreachable ();
+#if 0
+  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
+#endif
+}
+
+/* Conversions */
+
+/* Convert OP0 into a wide_int with parameters taken from TYPE.  If
+   the value does not fit, set OVERFLOW.  */
+
+wide_int
+wide_int::from_hwi (HOST_WIDE_INT op0, const_tree type, 
+		    bool *overflow)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return wide_int::from_uhwi (op0, prec, overflow);
+  else
+    return wide_int::from_shwi (op0, prec, overflow);
+}
+
+/* Convert signed OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+		     bool *overflow)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_shwi (op0, prec, overflow);
+}
+
+/* Convert unsigned OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode, 
+		     bool *overflow)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_uhwi (op0, prec, overflow);
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = sext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS is too large for
+   the mode's precision, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi () const
+{
+  return to_shwi (precision);
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = zext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS is too large for
+   the mode's precision, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi () const
+{
+  return to_uhwi (precision);
+}
+
+
+/* Convert OP0 of LEN into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT* op0, unsigned int len, 
+		      enum machine_mode mode)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_array (op0, len, prec);
+}
+
+/* Convert OP0 of LEN into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT* op0, unsigned int len, 
+		      const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return wide_int::from_array (op0, len, prec);
+}
+
+/* Convert double_int OP0 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_double_int (double_int op0, enum machine_mode mode)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_double_int (op0, prec);
+}
+
+/* Min and Max value helpers.  */
+
+/* Produce the largest SGNed number that is represented in PRECISION.
+   The result is represented in PRECISION.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (unsigned int precision, SignOp sgn)
+{
+  return max_value (precision, precision, sgn);
+}
+  
+/* Produce the largest number that is represented in MODE. The
+   precision are taken from mode.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (enum machine_mode mode, SignOp sgn)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+  return max_value (prec, prec, sgn);
+}
+
+/* Produce the largest number that is represented in TYPE. The
+   precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::max_value (const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  return max_value (prec, prec, TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+/* Produce the smallest SGNed number that is represented in PRECISION.
+   The result is represented in PRECISION.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::min_value (unsigned int precision, SignOp sgn)
+{
+  return min_value (precision, precision, sgn);
+}
+  
+/* Produce the smallest number that is represented in MODE. The
+   precision are taken from mode.  SGN must be SIGNED or UNSIGNED.  */
+
+wide_int
+wide_int::min_value (enum machine_mode mode, SignOp sgn)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+  return min_value (prec, prec, sgn);
+}
+
+/* Produce the smallest number that is represented in TYPE. The
+   precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::min_value (const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  return min_value (prec, prec, TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+
+/* Small constants.  */
+
+/* Return a wide int of -1 with precision PREC.  */
+
+wide_int
+wide_int::minus_one (unsigned int prec)
+{
+  return wide_int::from_shwi (-1, prec);
+}
+
+/* Return a wide int of 0 with precision PREC.  */
+
+wide_int
+wide_int::zero (unsigned int prec)
+{
+  return wide_int::from_shwi (0, prec);
+}
+
+/* Return a wide int of 1 with precision PREC.  */
+
+wide_int
+wide_int::one (unsigned int prec)
+{
+  return wide_int::from_shwi (1, prec);
+}
+
+/* Return a wide int of 2 with precision PREC.  */
+
+wide_int
+wide_int::two (unsigned int prec)
+{
+  return wide_int::from_shwi (2, prec);
+}
+
+/* Public accessors for the interior of a wide int.  */
+
+/* Get the number of host wide ints actually represented within the
+   wide int.  */
+
+unsigned short
+wide_int::get_len () const
+{
+  return len;
+}
+
+/* Get precision of the value represented within the wide int.  */
+
+unsigned int
+wide_int::get_precision () const
+{
+  return precision;
+}
+
+/* Get a particular element of the wide int.  */
+
+HOST_WIDE_INT
+wide_int::elt (unsigned int i) const
+{
+  return i >= len ? sign_mask () : val[i];
+}
+
+/* Return true if THIS is -1.  */
+
+bool
+wide_int::minus_one_p () const
+{
+  return len == 1 && val[0] == (HOST_WIDE_INT)-1;
+}
+
+/* Return true if THIS is 0.  */
+
+bool
+wide_int::zero_p () const
+{
+  return len == 1 && val[0] == 0;
+}
+
+/* Return true if THIS is 1.  */
+
+bool
+wide_int::one_p () const
+{
+  return len == 1 && val[0] == 1;
+}
+
+/* Return true if THIS is negative.  */
+
+bool
+wide_int::neg_p () const
+{
+  return sign_mask () != 0;
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently signed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+bool
+wide_int::operator == (const wide_int &op1) const
+{
+  bool result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = true;
+      goto ex;
+    }
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << precision) - 1;
+      result = (val[0] & mask) == (op1.val[0] & mask);
+      goto ex;
+    }
+
+  if (precision == HOST_BITS_PER_WIDE_INT)
+    {
+      result = val[0] == op1.val[0];
+      goto ex;
+    }
+
+  result = eq_p_large (op1);
+
+ ex:
+  return result;
+}
+
+/* Return true if THIS is not equal to OP1. */ 
+
+bool
+wide_int::operator != (const wide_int &op1) const
+{
+  return !(*this == op1);
+}  
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::lt_p (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (op1);
+  else
+    return ltu_p (op1);
+}  
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::gt_p (HOST_WIDE_INT op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return gts_p (op1);
+  else
+    return gtu_p (op1);
+}  
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::gt_p (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return op1.lts_p (*this);
+  else
+    return op1.ltu_p (*this);
+}  
+
+/* Return true if THIS is signed greater than OP1.  */
+
+bool
+wide_int::gts_p (const wide_int &op1) const
+{
+  return op1.lts_p (*this);
+}  
+
+/* Return true if THIS > OP1 using signed comparisons.  */
+
+bool
+wide_int::gts_p (const HOST_WIDE_INT op1) const
+{
+  bool result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] > sext_hwi (op1, precision);
+      goto ex;
+    }
+  
+  result = !neg_p ();
+
+ ex:
+  return result;
+}
+
+/* Return true if THIS is unsigned greater than OP1.  */
+
+bool
+wide_int::gtu_p (const wide_int &op1) const
+{
+  return op1.ltu_p (*this);
+}  
+
+/* Return true if THIS > OP1 using unsigned comparisons.  */
+
+bool
+wide_int::gtu_p (const unsigned HOST_WIDE_INT op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  if (precision < HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1, precision);
+
+      result = x0 > x1;
+    }
+  else
+    result = true;
+  return result;
+}
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+bool
+wide_int::lt_p (HOST_WIDE_INT op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (op1);
+  else
+    return ltu_p (op1);
+}  
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p (const HOST_WIDE_INT op1) const
+{
+  bool result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] < sext_hwi (op1, precision);
+      goto ex;
+    }
+  
+  result = neg_p ();
+
+ ex:
+  return result;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p (const wide_int &op1) const
+{
+  bool result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] < op1.val[0];
+      goto ex;
+    }
+
+  result = lts_p_large (op1);
+
+ ex:
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p (const unsigned HOST_WIDE_INT op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  if (precision < HOST_BITS_PER_WIDE_INT || len == 1)
+    {
+      x0 = zext_hwi (val[0], precision);
+      x1 = zext_hwi (op1, precision);
+
+      result = x0 < x1;
+    }
+  else
+    result = false;
+
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = false;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (op1.val[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = op1.val[0];
+	}
+
+      result = x0 < x1;
+      goto ex;
+    }
+
+  result = ltu_p_large (op1);
+
+ex:
+  return result;
+}
+
+/* Return -1 0 or 1 depending on how THIS compares with OP1.  Signness
+   is indicated by OP.  */
+
+int
+wide_int::cmp (const wide_int &op1, SignOp op) const
+{
+  if (op == SIGNED)
+    return cmps (op1);
+  else
+    return cmpu (op1);
+}  
+
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+int
+wide_int::cmps (const wide_int &op1) const
+{
+  int result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = 0;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      if (val[0] < op1.val[0])
+	{
+	  result = -1;
+	  goto ex;
+	}
+      if (val[0] > op1.val[0])
+	{
+	  result = 1;
+	  goto ex;
+	}
+    }
+
+  result = cmps_large (op1);
+
+ ex:
+  return result;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+int
+wide_int::cmpu (const wide_int &op1) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int result;
+
+  gcc_assert (precision == op1.precision);
+
+  if (this == &op1)
+    {
+      result = 0;
+      goto ex;
+    }
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (op1.val[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = op1.val[0];
+	}
+
+      if (x0 < x1)
+	result = -1;
+      else if (x0 == x1)
+	result = 0;
+      else
+	result = 1;
+      goto ex;
+    }
+
+  result = cmpu_large (op1);
+
+ ex:
+  return result;
+}
+
+
+/* Return the signed or unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::min (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return lts_p (op1) ? (*this) : op1;
+  else
+    return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed or unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::max (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return gts_p (op1) ? (*this) : op1;
+  else
+    return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed min of THIS and OP1. */
+
+wide_int
+wide_int::smin (const wide_int &op1) const
+{
+  return lts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed max of THIS and OP1. */
+
+wide_int
+wide_int::smax (const wide_int &op1) const
+{
+  return gts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::umin (const wide_int &op1) const
+{
+  return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::umax (const wide_int &op1) const
+{
+  return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p () const
+{
+  return only_sign_bit_p (precision);
+}
+
+/* Return true if THIS fits in a HOST_WIDE_INT with no loss of
+   precision.  */
+
+bool
+wide_int::fits_shwi_p () const
+{
+  return len == 1;
+}
+
+/* Return true if THIS fits in an unsigned HOST_WIDE_INT with no loss
+   of precision.  */
+
+bool
+wide_int::fits_uhwi_p () const
+{
+  return len == 1 
+    || (len == 2 && val[1] == 0);
+}
+
+/* Return THIS extended to PREC.  The signness of the extension is
+   specified by OP.  */
+
+wide_int 
+wide_int::ext (unsigned int prec, SignOp z) const
+{
+  if (z == UNSIGNED)
+    return zext (prec);
+  else
+    return sext (prec);
+}
+
+/* Return THIS forced to the precision of TYPE.  If this is extension,
+   the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (enum machine_mode mode, SignOp sgn) const
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (prec, sgn);
+}
+
+/* Return THIS forced to the precision and sign of TYPE.  If this is
+   extension, the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (const_tree type) const
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  SignOp sgn = TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED;
+
+  return force_to_size (prec, sgn);
+}
+
+/* Return THIS zero extended to the precision of TYPE but extends
+   using SGN.  If this is extension, the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (const_tree type, SignOp sgn) const
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (prec, sgn);
+}
+
+/* Return THIS forced to the precision of TYPE.  If this is extension,
+   it is signed. */
+
+wide_int 
+wide_int::sforce_to_size (enum machine_mode mode) const
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (prec, SIGNED);
+}
+
+/* Return THIS zero extended to the precision of TYPE but extends
+   using SGN.  If this is extension, it is signed. */
+
+wide_int 
+wide_int::sforce_to_size (const_tree type) const
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (prec, SIGNED);
+}
+
+/* Return THIS forced to the precision of TYPE.  If this
+   is extension, it is unsigned. */
+
+wide_int 
+wide_int::zforce_to_size (enum machine_mode mode) const
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (prec, UNSIGNED);
+}
+
+/* Return THIS zero extended to the precision of TYPE but extends
+   using SGN.  If this is extension, it is unsigned. */
+
+wide_int 
+wide_int::zforce_to_size (const_tree type) const
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (prec, UNSIGNED);
+}
+
+/*
+ * Logicals.
+ */
+
+/* Return THIS & OP1.  */
+
+wide_int
+wide_int::operator & (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] & op1.val[0];
+    }
+  else
+    result = and_large (op1);
+  
+  return result;
+}
+
+
+/* Return THIS & ~OP1.  */
+
+wide_int
+wide_int::and_not (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] & ~op1.val[0];
+    }
+  else
+    result = and_not_large (op1);
+  
+  return result;
+}
+
+
+/* Return the logical negation (bitwise complement) of THIS.  */
+
+wide_int
+wide_int::operator ~ () const
+{
+  wide_int result;
+  int l0 = len - 1;
+
+  result.len = len;
+  result.precision = precision;
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = ~val[l0];
+      l0--;
+    }
+
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+wide_int
+wide_int::operator | (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] | op1.val[0];
+    }
+  else
+    result = or_large (op1);
+  
+  return result;
+}
+
+
+/* Return THIS | ~OP1.  */
+
+wide_int
+wide_int::or_not (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] | ~op1.val[0];
+    }
+  else
+    result = or_not_large (op1);
+  
+  return result;
+}
+
+
+/* Return THIS ^ OP1.  */
+
+wide_int
+wide_int::operator ^ (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] ^ op1.val[0];
+    }
+  else
+    result = xor_large (op1);
+  
+  return result;
+}
+
+/*
+ * Integer arithmetic
+ */
+
+/* Return THIS + OP1.  */
+
+wide_int
+wide_int::operator + (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] + op1.val[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = add_large (op1);
+  
+  return result;
+}
+
+/* Multiply THIS and OP1.  The result is the same precision as the
+   operands, so there is no reason for signed or unsigned
+   versions.  */
+
+wide_int
+wide_int::operator * (const wide_int &op1) const
+{
+  bool overflow = false;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      wide_int result;
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] * op1.val[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+      return result;
+    }
+  else
+    return mul_internal (false, false, this, &op1, UNSIGNED, &overflow, false);
+}
+
+/* Negate THIS.  */
+
+wide_int
+wide_int::neg () const
+{
+  wide_int z = wide_int::from_shwi (0, precision);
+  return z - *this;
+}
+
+/* Negate THIS.  Set overflow if the value cannot be negated.  */
+
+wide_int
+wide_int::neg (bool *overflow) const
+{
+  wide_int z = wide_int::from_shwi (0, precision);
+  if (only_sign_bit_p ())
+    *overflow = true;
+
+  return z - *this;
+}
+
+/* Return THIS - OP1.  */
+
+wide_int
+wide_int::operator - (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] - op1.val[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = sub_large (op1);
+  
+  return result;
+}
+
+
+/* Signed multiply THIS and OP1.  The result is the same precision as
+   the operands.  OVERFLOW is set true if the result overflows.  */
+
+wide_int
+wide_int::smul (const wide_int &x, bool *overflow) const
+{
+  return mul (x, SIGNED, overflow);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is the same precision
+   as the operands.  OVERFLOW is set true if the result overflows.  */
+
+wide_int
+wide_int::umul (const wide_int &x, bool *overflow) const
+{
+  return mul (x, UNSIGNED, overflow);
+}
+
+/* Signed multiply THIS and OP1.  The result is twice the precision as
+   the operands.  */
+
+wide_int
+wide_int::smul_full (const wide_int &x) const
+{
+  return mul_full (x, SIGNED);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is twice the precision
+   as the operands.  */
+
+wide_int
+wide_int::umul_full (const wide_int &x) const
+{
+  return mul_full (x, UNSIGNED);
+}
+
+/* Signed divide with truncation of result.  */
+
+wide_int
+wide_int::sdiv_trunc (const wide_int &divisor) const
+{
+  return div_trunc (divisor, SIGNED);
+}
+
+/* Unsigned divide with truncation of result.  */
+
+wide_int
+wide_int::udiv_trunc (const wide_int &divisor) const
+{
+  return div_trunc (divisor, UNSIGNED);
+}
+
+/* Unsigned divide with floor truncation of result.  */
+
+wide_int
+wide_int::udiv_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return div_floor (divisor, UNSIGNED, &overflow);
+}
+
+/* Signed divide with floor truncation of result.  */
+
+wide_int
+wide_int::sdiv_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return div_floor (divisor, SIGNED, &overflow);
+}
+
+/* Signed divide/mod with truncation of result.  */
+
+wide_int
+wide_int::sdivmod_trunc (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_trunc (divisor, mod, SIGNED);
+}
+
+/* Unsigned divide/mod with truncation of result.  */
+
+wide_int
+wide_int::udivmod_trunc (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_trunc (divisor, mod, UNSIGNED);
+}
+
+/* Signed divide/mod with floor truncation of result.  */
+
+wide_int
+wide_int::sdivmod_floor (const wide_int &divisor, wide_int *mod) const
+{
+  return divmod_floor (divisor, mod, SIGNED);
+}
+
+/* Signed mod with truncation of result.  */
+
+wide_int
+wide_int::smod_trunc (const wide_int &divisor) const
+{
+  return mod_trunc (divisor, SIGNED);
+}
+
+/* Unsigned mod with truncation of result.  */
+
+wide_int
+wide_int::umod_trunc (const wide_int &divisor) const
+{
+  return mod_trunc (divisor, UNSIGNED);
+}
+
+/* Unsigned mod with floor truncation of result.  */
+
+wide_int
+wide_int::umod_floor (const wide_int &divisor) const
+{
+  bool overflow;
+
+  return mod_floor (divisor, UNSIGNED, &overflow);
+}
+
+/* If SHIFT_COUNT_TRUNCATED is defined, truncate CNT.   
+
+   At first look, the shift truncation code does not look right.
+   Shifts (and rotates) are done according to the precision of the
+   mode but the shift count is truncated according to the bitsize of
+   the mode.  This is how real hardware works (Knuth's mix machine is
+   the only known exception to this rule, but it was never real).
+
+   On an ideal machine, like Knuth's mix machine, a shift count is a
+   word long and all of the bits of that word are examined to compute
+   the shift amount.  But on real hardware, especially on machines
+   with fast (single cycle shifts) that takes too long.  On these
+   machines, the amount of time to perform a shift dictates the cycle
+   time of the machine so corners are cut to keep this fast.  A
+   comparison of an entire 64 bit word would take something like 6
+   gate delays before the shifting can even start.
+
+   So real hardware only looks at a small part of the shift amount.
+   On ibm machines, this tends to be 1 more than what is necessary to
+   encode the shift amount.  The rest of the world looks at only the
+   minimum number of bits.  This means that only 3 gate delays are
+   necessary to set up the shifter.
+
+   On the other hand, right shifts and rotates must be according to
+   the precision or the operation does not make any sense.   */
+inline int
+wide_int::trunc_shift (int cnt, unsigned int bitsize)
+{
+#ifdef SHIFT_COUNT_TRUNCATED
+  cnt = cnt & (bitsize - 1);
+#endif
+  return cnt;
+}
+
+/* This function is called in two contexts.  If OP == TRUNC, this
+   function provides a count that matches the semantics of the target
+   machine depending on the value of SHIFT_COUNT_TRUNCATED.  Note that
+   if SHIFT_COUNT_TRUNCATED is not defined, this function may produce
+   -1 as a value if the shift amount is greater than the bitsize of
+   the mode.  -1 is a surrogate for a very large amount.
+
+   If OP == NONE, then this function always truncates the shift value
+   to the bitsize because this shifting operation is a function that
+   is internal to GCC.  */
+
+inline int
+wide_int::trunc_shift (const wide_int &cnt, unsigned int bitsize, 
+		       ShiftOp trunc_op)
+{
+  if (trunc_op == TRUNC)
+    {
+#ifdef SHIFT_COUNT_TRUNCATED
+      return cnt.val[0] & (bitsize - 1);
+#else
+      if (cnt.ltu (bitsize))
+	return cnt.val[0] & (bitsize - 1);
+      else 
+	return -1;
+#endif
+    }
+  else
+    return cnt.val[0] & (bitsize - 1);
+}
+
+/* Left shift by an integer Y.  See the definition of Op.TRUNC for how
+   to set TRUNC_OP.  BITSIZE is used to properly adjust the shift amount.  */
+
+wide_int
+wide_int::lshift (unsigned int y, unsigned int bitsize, 
+		  ShiftOp trunc_op) const
+{
+  return lshift (y, precision, bitsize, trunc_op);
+}
+
+/* Left shifting by an wide_int shift amount.  See the definition of
+   Op.TRUNC for how to set TRUNC_OP.  */
+
+wide_int
+wide_int::lshift (const wide_int &y, unsigned int bitsize, 
+		  ShiftOp trunc_op) const
+{
+  if (trunc_op == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (y, bitsize, TRUNC);
+      if (shift == -1)
+	return wide_int::zero (precision);
+      return lshift (shift, precision, bitsize, NONE);
+    }
+  else
+    return lshift (trunc_shift (y, bitsize, NONE), precision, bitsize, NONE);
+}
+
+/* Left shift THIS by CNT.  See the definition of Op.TRUNC for how to
+   set TRUNC_OP.  Since this is used internally, it has the ability to
+   specify the PRECISION and BITSIZE independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+wide_int
+wide_int::lshift (unsigned int cnt, unsigned int res_prec, 
+		  unsigned int bs, ShiftOp op) const
+{
+  wide_int result;
+
+  if (op == TRUNC)
+    cnt = trunc_shift (bs, cnt);
+
+  /* Handle the simple case quickly.   */
+  if (res_prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.precision = res_prec;
+      result.len = 1;
+      result.val[0] = val[0] << cnt;
+    }
+  else
+    result = lshift_large (cnt, res_prec);
+
+  return result;
+}
+
+/* Rotate THIS left by Y within its precision.  */
+
+wide_int
+wide_int::lrotate (const wide_int &y) const
+{
+  return lrotate (y.val[0]);
+}
+
+
+/* Unsigned right shift by Y.  See the definition of Op.TRUNC for how
+   to set TRUNC_OP. BITSIZE is the bitsize of the word that the value must be
+   shifted in. */
+
+wide_int
+wide_int::rshiftu (const wide_int &y, unsigned int bitsize,
+		   ShiftOp trunc_op) const
+{
+  if (trunc_op == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (y, bitsize, TRUNC);
+      if (shift == -1)
+	return wide_int::zero (precision);
+      return rshiftu (shift, bitsize, NONE);
+    }
+  else
+    return rshiftu (trunc_shift (y, bitsize, NONE), bitsize, NONE);
+}
+
+/* Right shift THIS by Y.  SGN indicates the sign.  TRUNC_OP indicates the
+   truncation option.  */
+
+wide_int
+wide_int::rshift (const wide_int &y, SignOp sgn, unsigned int bitsize,
+		  ShiftOp trunc_op) const
+{
+  if (sgn == UNSIGNED)
+    return rshiftu (y, bitsize, trunc_op);
+  else
+    return rshifts (y, bitsize, trunc_op);
+}
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set TRUNC_OP.  */
+
+wide_int
+wide_int::rshiftu (unsigned int cnt, unsigned int bitsize, 
+		   ShiftOp trunc_op) const
+{
+  wide_int result;
+
+  if (trunc_op == TRUNC)
+    cnt = trunc_shift (cnt, bitsize);
+
+  if (cnt == 0)
+    result = copy ();
+  
+  else if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* Handle the simple case quickly.   */
+      unsigned HOST_WIDE_INT x = val[0];
+
+      result.precision = precision;
+      result.len = 1;
+
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	x = zext_hwi (x, precision);
+
+      result.val[0] = x >> cnt;
+    }
+  else 
+    result = rshiftu_large (cnt);
+
+  return result;
+}
+
+/* Signed right shift by Y.  See the definition of Op.TRUNC for how to
+   set TRUNC_OP.  */
+wide_int
+wide_int::rshifts (const wide_int &y, unsigned int bitsize, 
+		   ShiftOp trunc_op) const
+{
+  if (trunc_op == TRUNC)
+    {
+      HOST_WIDE_INT shift = trunc_shift (y, bitsize, TRUNC);
+      if (shift == -1)
+	{
+	  /* The value of the shift was larger than the bitsize and this
+	     machine does not truncate the value, so the result is
+	     a smeared sign bit.  */
+	  if (neg_p ())
+	    return wide_int::minus_one (precision);
+	  else
+	    return wide_int::zero (precision);
+	}
+      return rshifts (shift, NONE);
+    }
+  else
+    return rshifts (trunc_shift (y, bitsize, NONE), bitsize, NONE);
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set TRUNC_OP.  */
+
+wide_int
+wide_int::rshifts (unsigned int cnt, unsigned int bitsize, 
+		   ShiftOp trunc_op) const
+{
+  wide_int result;
+
+  if (trunc_op == TRUNC)
+    cnt = trunc_shift (cnt, bitsize);
+
+  if (cnt == 0)
+    result = copy ();
+  else if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* Handle the simple case quickly.   */
+      HOST_WIDE_INT x = val[0];
+
+      result.precision = precision;
+      result.len = 1;
+      result.val[0] = x >> cnt;
+    }
+  else
+    result = rshifts_large (cnt);
+
+  return result;
+}
+
+/* Rotate THIS right by Y within its precision.  */
+
+wide_int
+wide_int::rrotate (const wide_int &y) const
+{
+  return rrotate (y.val[0]);
+}
+
+/* tree related routines.  */
+
+extern tree wide_int_to_tree (tree type, const wide_int &cst);
+extern tree wide_int_to_infinite_tree (tree type, const wide_int &cst, 
+				       unsigned int prec);
+extern tree force_fit_type_wide (tree, const wide_int &, int, bool);
+
+/* real related routines.  */
+extern wide_int real_to_integer (const REAL_VALUE_TYPE *, bool *, int, int);
+extern wide_int decimal_real_to_integer (const REAL_VALUE_TYPE *, bool *, int, int);
+
+
+/* Conversion to and from GMP integer representations.  */
+
+void mpz_set_wide_int (mpz_t, wide_int, bool);
+wide_int mpz_get_wide_int (const_tree, mpz_t, bool);
+#endif /* GENERATOR FILE */
+
+#endif /* WIDE_INT_H */

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-03 19:18                                                                                     ` Kenneth Zadeck
@ 2013-04-04 11:45                                                                                       ` Richard Biener
  2013-04-08  5:28                                                                                         ` Comments on the suggestion to use infinite precision math for wide int Kenneth Zadeck
  2013-04-22 21:39                                                                                         ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Richard Sandiford
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Biener @ 2013-04-04 11:45 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On Wed, Apr 3, 2013 at 6:16 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> On 04/03/2013 09:53 AM, Richard Biener wrote:
>>
>> On Wed, Apr 3, 2013 at 2:05 PM, Kenneth Zadeck <zadeck@naturalbridge.com>
>> wrote:
>>>
>>> On 04/03/2013 05:17 AM, Richard Biener wrote:
>>>
>>>> In the end you will have a variable-size storage in TREE_INT_CST thus
>>>> you will have at least to emit _code_ copying over meta-data and data
>>>> from the tree representation to the wide-int (similar for RTX
>>>> CONST_DOUBLE/INT).
>>>> I'm objecting to the amount of code you emit and agree that the runtime
>>>> cost is copying the meta-data (hopefully optimizable via CSE / SRA)
>>>> and in most cases one (or two) iterations of the loop copying the data
>>>> (not optimizable).
>>>
>>> i did get rid of the bitsize in the wide-int patch so at this point the
>>> meta
>>> data is the precision and the len.
>>> not really a lot here.   As usual we pay a high price in gcc for not
>>> pushing
>>> the tree rep down into the rtl level, then it would have been acceptable
>>> to
>>> have the tree type bleed into the wide-int code.
>>>
>>>
>>>
>>>>> 2)  You present this as if the implementor actually should care about
>>>>> the
>>>>> implementation and you give 3 alternatives:  the double_int, the
>>>>> current
>>>>> one, and HWI.     We have tried to make it so that the client should
>>>>> not
>>>>> care.   Certainly in my experience here, I have not found a place to
>>>>> care.
>>>>
>>>> Well, similar as for the copying overhead for tree your approach
>>>> requires
>>>> overloading operations for HOST_WIDE_INT operands to be able to
>>>> say wi + 1 (which is certainly desirable), or the overhead of using
>>>> wide_int_one ().
>>>>
>>>>> In my opinion double_int needs to go away.  That is the main thrust of
>>>>> my
>>>>> patches.   There is no place in a compiler for an abi that depends on
>>>>> constants fitting into 2 two words whose size is defined by the host.
>>>>
>>>> That's true.  I'm not arguing to preserve "double-int" - I'm arguing to
>>>> preserve a way to ask for an integer type on the host with (at least)
>>>> N bits.  Almost all double-int users really ask for an integer type on
>>>> the
>>>> host that has at least as many bits as the pointer representation (or
>>>> word_mode) on
>>>> the target (we do have HOST_WIDEST_INT == 32bits for 64bit pointer
>>>> targets).  No double-int user specifically wants 2 * HOST_WIDE_INT
>>>> precision - that is just what happens to be there.  Thus I am providing
>>>> a way to say get me a host integer with at least N bits (VRP asks for
>>>> this, for example).
>>>>
>>>> What I was asking for is that whatever can provide the above should
>>>> share
>>>> the functional interface with wide-int (or the othert way around).  And
>>>> I
>>>> was claiming that wide-int is too fat, because current users of
>>>> double-int
>>>> eventually store double-ints permanently.
>>>
>>> The problem is that, in truth, double int is too fat. 99.something% of
>>> all
>>> constants fit in 1 hwi and that is likely to be true forever (i
>>> understand
>>> that tree vpn may need some thought here).  The rtl level, which has, for
>>> as
>>> long as i have known it, had 2 reps for integer constants. So it was
>>> relatively easy to slide the CONST_WIDE_INT in.  It seems like the right
>>> trickery here rather than adding a storage model for wide-ints might be a
>>> way to use the c++ to invisibly support several (and by "several" i
>>> really
>>> mean 2) classes of TREE_CSTs.
>>
>> The truth is that _now_ TREE_INT_CSTs use double-ints and we have
>> CONST_INT and CONST_DOUBLE.  What I (and you) propose would
>> get us to use variable-size storage for both, allowing to just use a
>> single
>> HOST_WIDE_INT in the majority of cases.  In my view the constant
>> length of the variable-size storage for TREE_INT_CSTs is determined
>> by its type (thus, it doesn't have "optimized" variable-size storage
>> but "unoptimized" fixed-size storage based on the maximum storage
>> requirement for the type).  Similar for RTX CONST_INT which would
>> have fixed-size storage based on the mode-size of the constant.
>> Using optimized space (thus using the encoding properties) requires you
>> to fit the 'short len' somewhere which possibly will not pay off in the
>> end
>> (for tree we do have that storage available, so we could go with optimized
>> storage for it, not sure with RTL, I don't see available space there).
>
> There are two questions here:   one is the fact that you object to the fact
> that we represent small constants efficiently

Huh?  Where do I object to that?  I question that for the storage in tree
and RTX the encoding trick pays off if you need another HWI-aligned
word to store the len.  But see below.

> and the second is that we take
> advantage of the fact that fixed size stack allocation is effectively free
> for short lived objects like wide-ints (as i use them).

I don't question that and I am not asking you to change that.  As part of
what I ask for a more optimal (smaller) stack allocation would be _possible_
(but not required).

> At the rtl level your idea does not work.   rtl constants do not have a mode
> or type.    So if you do not compress, how are you going to determine how
> many words you need for the constant 1.   I would love to have a rep that
> had the mode in it.    But it is a huge change that requires a lot of
> hacking to every port.

Quoting from your RTL parts patch:

+struct GTY((variable_size)) hwivec_def {
+  int num_elem;                /* number of elements */
+  HOST_WIDE_INT elem[1];
+};
+
+#define HWI_GET_NUM_ELEM(HWIVEC)       ((HWIVEC)->num_elem)
+#define HWI_PUT_NUM_ELEM(HWIVEC, NUM)  ((HWIVEC)->num_elem = (NUM))
+
 /* RTL expression ("rtx").  */

 struct GTY((chain_next ("RTX_NEXT (&%h)"),
@@ -343,6 +352,7 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"),
     struct block_symbol block_sym;
     struct real_value rv;
     struct fixed_value fv;
+    struct hwivec_def hwiv;
   } GTY ((special ("rtx_def"), desc ("GET_CODE (&%0)"))) u;
 };

that 'wastes' one HOST_WIDE_INT.  So the most efficient encoding
of 0 will require two HOST_WIDE_INT size storage.  Same as for
double-int currently.  99.9% of all constants will fit into two
HOST_WIDE_INTs, thus having the variable size encoding for
the storage in RTX (as opposed to having num_elem == GET_MODE_BITSIZE
/ HOST_BITS_PER_WIDE_INT) is a waste of time.  num_elem
for a non-optimized encoding is available from the mode stored in
the integer constant RTX...

You say

> At the rtl level your idea does not work.   rtl constants do not have a mode
> or type.

Which is not true and does not matter.  I tell you why.  Quote:

+#if TARGET_SUPPORTS_WIDE_INT
+
+/* Match CONST_*s that can represent compile-time constant integers.  */
+#define CASE_CONST_SCALAR_INT \
+   case CONST_INT: \
+   case CONST_WIDE_INT

which means you are only replacing CONST_DOUBLE with wide-int.
And _all_ CONST_DOUBLE have a mode.  Otherwise you'd have no
way of creating the wide-int in the first place.  Which means any
future transition of CONST_INT to the wide-int code (which is desirable!)
will need to fix the fact that CONST_INTs do not have a mode.
Or even simpler - just retain CONST_INT behavior!  CONST_INTs
need a single HWI storage (moving that to wide-int with a len field
regresses here) and CONST_INTs are always sign-extended.
Preserve that!  Make VOIDmode integer constants have a single
HWI as storage, sign-extended.

> I understand that this makes me vulnerable to the argument that we should
> not let the rtl level ever dictate anything about the tree level, but the
> truth is that a variable len rep is almost always used for big integers.
> In our code, most constants of large types are small numbers.   (Remember i
> got into this because the tree constant prop thinks that left shifting any
> number by anything greater than 128 is always 0 and discovered that that was
> just the tip of the iceberg.) But mostly i support the decision to canonize
> numbers to the smallest number of HWIs because most of the algorithms to do
> the math can be short circuited.    I admit that if i had to effectively
> unpack most numbers to do the math, that the canonization would be a waste.
> However, this is not really relevant to this conversation.   Yes, you could
> get rid of the len, but this such a small part of picture.

Getting rid of 'len' in the RTX storage was only a question of whether it
is an efficient way to go forward.  And with considering to unify
CONST_INTs and CONST_WIDE_INTs it is not.  And even for CONST_WIDE_INTs
(which most of the time would be 2 HWI storage, as otherwise you'd use
a CONST_INT) it would be an improvement.

> Furthermore, I am constrained at the rtl level because it is just too dirty
> to share the storage.   We tried that and the amount of whack a mole we were
> playing was killing us.

The above argument (not encode len explicitely in the RTX) is unrelated
to "sharing the storage" (whatever you exactly refer to here).

> I am comfortable making big changes at the portable level because i can
> easily test them, but changes to fundamental data structures inside every
> port is more than i am willing to do.   If you are going to do that, then
> you are going to have start giving rtl constants modes and that is a huge
> change (that while desirable i cannot do).

All CONST_DOUBLEs have modes.  You do not touch CONST_INTs.
VOIDmode CONST_WIDE_INTs seem perfectly possible to me (see above).
So nothing to fix, even if that is desirable as you say and as I agree.

> At the tree level you could share the storage, I admit that that is easy, i
> just do not think that it is desirable.  The stack allocation inside the
> wide-int is very cheap and the fact that the number that comes out is almost
> always one hwi makes this very efficient.   Even if I was starting from
> scratch this would be a strong contender to be the right representation.
>
> Fundamentally, i do not believe that the amount of copying that i am
> proposing at the tree level will be significant.  Yes, if you force me to
> use an uncompressed format you can make what i propose expensive.

An uncompressed format at tree / RTX will in 99.9% of all cases be
one or two HWIs.  Realize that all my arguments and requests are
really independent (even though I make them together).

As we now have the power of C++ and templates I see no good reason
to not do the optimization of eliding the copying from the RTX / tree
representation.  It can be done as a followup I guess (with the disadvantage
of leaving the possibility to "optimize" existing converted client code).

Btw, is the current state of the patches accessible as a branch somewhere?

>>>>> This is not a beauty contest argument, we have public ports are
>>>>> beginning
>>>>> to
>>>>> use modes that are larger than two x86-64 HWIs and i have a private
>>>>> port
>>>>> that has such modes and it is my experience that any pass that uses
>>>>> this
>>>>> interface has one of three behaviors: it silently gets the wrong
>>>>> answer,
>>>>> it
>>>>> ices, or it fails to do the transformation.  If we leave double_int as
>>>>> an
>>>>> available option, then any use of it potentially will have one of these
>>>>> three behaviors.  And so one of my strong objections to this direction
>>>>> is
>>>>> that i do not want to fight this kind of bug for the rest of my life.
>>>>> Having a single storage model that just always works is in my opinion a
>>>>> highly desirable option.  What you have never answered in a concrete
>>>>> manner
>>>>> is, if we decide to provide this generality, what it would be used for.
>>>>> There is no place in a portable compiler where the right answer for
>>>>> every
>>>>> target is two HOST wide integers.
>>>>>
>>>>> However, i will admit that the HWI option has some merits.   We try to
>>>>> address this in our implementation by dividing what is done inline in
>>>>> wide-int.h to the cases that fit in an HWI and then only drop into the
>>>>> heavy
>>>>> code in wide-int.c if mode is larger (which it rarely will be).
>>>>> However, a
>>>>> case could be made that for certain kinds of things like string lengths
>>>>> and
>>>>> such, we could use another interface or as you argue, a different
>>>>> storage
>>>>> model with the same interface.   I just do not see that the cost of the
>>>>> conversion code is really going to show up on anyone's radar.
>>>>
>>>> What's the issue with abstracting away the model so a fixed-size 'len'
>>>> is possible?  (let away the argument that this would easily allow an
>>>> adaptor to tree)
>>>
>>> I have a particularly pessimistic perspective because i have already
>>> written
>>> most of this patch.   It is not that i do not want to change that code,
>>> it
>>> is that i have seen a certain set of mistakes that were made and i do not
>>> want to fix them more than once.   At the rtl level you can see the
>>> transition from only supporting 32 bit ints to supporting 64 bit its to
>>> finally supporting two HWIs and that transition code is not pretty.  My
>>> rtl
>>> patch fixes the places where an optimization was only made if the data
>>> type
>>> was 32 bits or smaller as well as the places where the optimization was
>>> made
>>> only if the data type is smaller than 64 bits (in addition to fixing all
>>> of
>>> the places where the code ices or simply gets the wrong answer if it is
>>> larger than TImode.)  The tree level is only modestly better, I believe
>>> only
>>> because it is newer. I have not seen any 32 bit only code, but it is
>>> littered with transformations that only work for 64 bits.   What is that
>>> 64
>>> bit only code going to look like in 5 years?
>>
>> The user interface of wide-int does not depend on whether a storage model
>> is abstracted or not.  If you take advantage of the storage model by
>> making its interface leaner then it will.  But I guess converting
>> everything
>> before settling on the wide-int interface may not have been the wisest
>> choice in the end (providing a wide-int that can literally replace
>> double-int
>> would have got you testing coverage without any change besides
>> double-int.[ch] and wide-int.[ch]).
>
> I think that it was exactly the correct decision.   We have made significant
> changes to the structure as we have gone along.   I have basically done most
> of what you have suggested, (the interface is completely functional, i got
> rid of the bitsize...)   What you are running into is that mike stump,
> richard sandiford and myself actually believe that the storage model is a
> fundamentally bad idea.

Well, that must be because of C++ ignorance.  Let's keep that issue
aside for now.  Be sure I'll come back to it.

>>> I want to make it easier to write the general code than to write the code
>>> that only solves the problem for the size port that the implementor is
>>> currently working on.   So I perceive the storage model as a way to keep
>>> having to fight this battle forever because it will allow the implementor
>>> to
>>> make a decision that the optimization only needs to be done for a
>>> particular
>>> sized integer.
>>>
>>> However, i get the fact that from your perspective, what you really want
>>> is
>>> a solution to the data structure problem in tree-vrp.
>>
>> No, that's just a convenient example.  What I really want is a wide-int
>> that is less visibly a replacement for CONST_DOUBLE.
>
> I think that that is unfair.   Variable length reps are the standard
> technique for doing wide math.  I am just proposing using data structures
> that are common best practices in the rest of the world and adapting them so
> that they match the gcc world better than just hacking in a gmp interface.

I don't object to variable-length reps.  I question the need of 'bitsize'
(gone! yay!) and now 'precision' in class wide_int.  I question the need
and efficiency of encoding 'len' in RTX CONST_WIDE_INT.

>>>   My patch for tree vrp
>>> scans the entire function to find the largest type used in the function
>>> and
>>> then does all of the math at 2x that size.  But i have to admit that i
>>> thought it was weird that you use tree cst as your long term storage.
>>> If
>>> this were my pass, i would have allocated a 2d array of some type that
>>> was
>>> as large as the function in 1d and twice as large as the largest int used
>>> in
>>> the other dimension and not overloaded tree-cst and then had a set of
>>> friend
>>> functions in double int to get in and out. Of course you do not need
>>> friends
>>> in double int because the rep is exposed, but in wide-int that is now
>>> hidden
>>> since it now is purely functional.
>>>
>>> I just have to believe that there is a better way to do tree-vrp than
>>> messing up wide-int for the rest of the compiler.
>>
>> It's not "messing up", it's making wide-int a generally useful thing and
>> not tying it so closely to RTL.
>
> Again, this is unfair.
>
>>
>>>>> 3) your trick will work at the tree level, but not at the rtl level.
>>>>> The
>>>>> wide-int code cannot share storage with the CONST_INTs.    We tried
>>>>> this,
>>>>> and there are a million bugs that would have to be fixed to make it
>>>>> work.
>>>>> It could have worked if CONST_INTs had carried a mode around, but since
>>>>> they
>>>>> do not, you end up with the same CONST_INT sharing the rep for several
>>>>> different types and that just did not work unless you are willing to do
>>>>> substantial cleanups.
>>>>
>>>> I don't believe you.  I am only asking for the adaptors to tree and RTL
>>>> to
>>>> work in an RVALUE-ish way (no modification, as obviously RTL and tree
>>>> constants may be shared).  I think your claim is because you have that
>>>> precision and bitsize members in your wide-int which I believe is a
>>>> design red herring.  I suppose we should concentrate on addressing that
>>>> one first.  Thus, let me repeat a few questions on your design to
>>>> eventually
>>>> let you understand my concerns:
>>>>
>>>> Given two wide-ints, a and b, what precision will the result of
>>>>        a + b
>>>> have?  Consider a having precision 32 and b having precision 64
>>>> on a 32-bit HWI host.
>>>>
>>>> You define wide-int to have no sign information:
>>>>
>>>> +   The representation does not contain any information about
>>>> +   signedness of the represented value, so it can be used to represent
>>>> +   both signed and unsigned numbers.  For operations where the results
>>>> +   depend on signedness (division, comparisons), the signedness must
>>>> +   be specified separately.  For operations where the signness
>>>> +   matters, one of the operands to the operation specifies either
>>>> +   wide_int::SIGNED or wide_int::UNSIGNED.
>>>>
>>>> but the result of operations on mixed precision operands _does_ depend
>>>> on the sign, nevertheless most operations do not get a signedness
>>>> argument.
>>>> Nor would that help, because it depends on the signedness of the
>>>> individual
>>>> operands!
>>>>
>>>> double-int get's around this by having a common "precision" to which
>>>> all smaller precision constants have to be sign-/zero-extended.  So
>>>> does CONST_INT and CONST_DOUBLE.
>>>>
>>>> Note that even with same precision you have introduced the same problem
>>>> with the variable len.
>>>>
>>>> My proposal is simple - all wide-ints are signed!  wide-int is basically
>>>> an arbitrary precision signed integer format.  The sign is encoded in
>>>> the most significant bit of the last active HWI of the representation
>>>> (val[len - 1] & (1 << HOST_BITS_PER_WIDE_INT - 1)).  All values
>>>> with less precision than len * HOST_BITS_PER_WIDE_INT are
>>>> properly sign-/zero-extended to precision len * HOST_BITS_PER_WIDE_INT.
>>>>
>>>> This let's you define mixed len operations by implicitely
>>>> sign-/zero-extending
>>>> the operands to whatever len is required for the operation.
>>>>
>>>> Furthermore it allows you to get rid of the precision member (and
>>>> bitsize anyway).
>>>> Conversion from tree / RTL requires information on the signedness of the
>>>> input (trivial for tree, for RTL all constants are signed - well,
>>>> sign-extended).
>>>> Whenever you want to transfer the wide-int to tree / RTL you have to
>>>> sign-/zero-extend according to the desired precision.  If you need sth
>>>> else
>>>> than arbitrary precision arithmetic you have to explicitely truncate /
>>>> extend
>>>> at suitable places - with overflow checking being trivial here.  For
>>>> optimization
>>>> purposes selected operations may benefit from a combined implementation
>>>> receiving a target precision and signedness.  Whatever extra meta-data
>>>> RTL requires does not belong in wide-int but in the RTX.  Trivially
>>>> a mode comes to my mind (on tree we have a type), and trivially
>>>> each RTX has a mode.  And each mode has a precision and bitsize.
>>>> It lacks a sign, so all RTL integer constants are sign-extended for
>>>> encoding efficiency purposes.  mixed-mode operations will not
>>>> occur (mixed len operations will), mixed-mode ops are exclusively
>>>> sign-/zero-extensions and truncations.
>>>>
>>>> Representation of (unsigned HOST_WIDE_INT)-1 would necessarily
>>>> be { 0, (unsigned HOST_WIDE_INT)-1 }, representation of -1 in any
>>>> precision would be { -1 }.
>>>>
>>>> That was my proposal.  Now, can you please properly specify yours?
>>
>> And you chose to not answer that fundamental question of how your
>> wide-int is _supposed_ to work?  Ok, maybe I shouldn't have distracted
>> you with the bits before this.
>
> sorry, i missed this question by accident.
>
> we did not do infinite precision by design.   We looked at the set of
> programming languages that gcc either compiles or might compile and we
> looked at the set of machines that gcc targets and neither of these two sets
> of entities define their operations in terms of infinite precision math.
> They always do math within a particular precision.    Scripting languages do
> use infinite precision but gcc does not compile any of them.   So unless you
> are going to restrict your set of operations to those that satisfy the
> properties of a ring, it is generally not strictly safe to do your math in
> infinite precision.
>
> we do all of the math in the precision defined by the types or modes that
> are passed in.
>
> constants are defined to be the size of the precision unless they can be
> compressed.   The len field tells how many words are actually needed to
> exactly represent the constant if (len-1)*HOST_WIDE_BITS_PER_WIDE_INT is
> less than the precision. The decompression process is to add a number of
> words to the high order side of the number.   These words must contain a
> zero if the highest represented bit is 0 and -1 if the highest represented
> bit is 1.

So the compressed representation is signed.  Please document that.

> i.e. this looks a lot like sign extension, but the numbers them selves are
> not inherently signed or unsigned as in your representation.    It is up to
> the operators to imply the signess. So the unsigned multiply operation is
> different than the signed multiply operation.    But these are applied to
> the bits without an interpretation of their sign.

Which means that the inconsistency of ops getting a precision argument
vs. arbitrarily taking the precision of the first operand is a design bug.
Note that with your encoding scheme as far as I understand the "sign"
of { -1 } depends on the precision.  If the precision is less than that of HWI
then { -1 } is signed, if it is exactly the precision of HWI the sign is
unspecified, it could be -1U or -1 (as far as I understand it is not an
invalid encoding of -1U?), if it has bigger precision than that of HWI
then the sign is unspecified (it could be -1U or -1 in larger precision)?

"Unspecified sign" means that you cannot combine two operands with
different 'len' / 'precision' without knowing the sign of the operands you
need to extend.  Note that knowing the sign of the operation is not enough.

So I believe that for correctness you need to assert at least
gcc_assert that operands have the same precision - as you assume
here for example:

+wide_int
+wide_int::operator + (const wide_int &op1) const
+{
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.bitsize = bitsize;
+      result.precision = precision;
+      result.val[0] = val[0] + op1.val[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+       result.val[0] = sext_hwi (result.val[0], precision);
+    }

which is clearly wrong if op1.precision != precision.  It also explains
why wide_int::one needs a precision ... (I hope you got rid of the
overloads)

I'm not sure to what extent you got rid of the precision/bitsize taking
functions like

+  inline wide_int lshift (unsigned int y, ShiftOp z, unsigned int bitsize,
+                         unsigned int precision) const;
+  wide_int popcount (unsigned int bitsize, unsigned int prec) const;

already.  They don't make sense as *this already has a precision.

Btw, my proposal would be to get rid of 'precision', as 'precision' is
not needed to interpret the encoding as I would define it (the MSB
would _always_ be a sign-bit) and as you say the operation
has a sign.  Truncating to a desired target precision can be done
after the fact or as part of the operation.  You already have to
deal with extension as even with equal precision operands can
have a different len.

I'd like to see the current state of wide-int somewhere btw., given
you've done significant changes since the last post.

Thanks,
Richard.

>
>> Richard.
>>
>>>> Thanks,
>>>> Richard.
>>>>
>>>>> On 04/02/2013 11:04 AM, Richard Biener wrote:
>>>>>>
>>>>>> On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck
>>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>>>
>>>>>>> This patch contains a large number of the changes requested by Richi.
>>>>>>> It
>>>>>>> does not contain any of the changes that he requested to abstract the
>>>>>>> storage layer.   That suggestion appears to be quite unworkable.
>>>>>>
>>>>>> I of course took this claim as a challenge ... with the following
>>>>>> result.
>>>>>> It is
>>>>>> of course quite workable ;)
>>>>>>
>>>>>> The attached patch implements the core wide-int class and three
>>>>>> storage
>>>>>> models (fixed size for things like plain HWI and double-int, variable
>>>>>> size
>>>>>> similar to how your wide-int works and an adaptor for the double-int
>>>>>> as
>>>>>> contained in trees).  With that you can now do
>>>>>>
>>>>>> HOST_WIDE_INT
>>>>>> wi_test (tree x)
>>>>>> {
>>>>>>      // template argument deduction doesn't do the magic we want it to
>>>>>> do
>>>>>>      // to make this kind of implicit conversions work
>>>>>>      // overload resolution considers this kind of conversions so we
>>>>>>      // need some magic that combines both ... but seeding the
>>>>>> overload
>>>>>>      // set with some instantiations doesn't seem to be possible :/
>>>>>>      // wide_int<> w = x + 1;
>>>>>>      wide_int<> w;
>>>>>>      w += x;
>>>>>>      w += 1;
>>>>>>      // template argument deduction doesn't deduce the return value
>>>>>> type,
>>>>>>      // not considering the template default argument either ...
>>>>>>      // w = wi (x) + 1;
>>>>>>      // we could support this by providing rvalue-to-lvalue promotion
>>>>>>      // via a traits class?
>>>>>>      // otoh it would lead to sub-optimal code anyway so we should
>>>>>>      // make the result available as reference parameter and only
>>>>>> support
>>>>>>      // wide_int <> res; add (res, x, 1); ?
>>>>>>      w = wi (x).operator+<wide_int<> >(1);
>>>>>>      wide_int<>::add(w, x, 1);
>>>>>>      return w.to_hwi ();
>>>>>> }
>>>>>>
>>>>>> we are somewhat limited with C++ unless we want to get really fancy.
>>>>>> Eventually providing operator+ just doesn't make much sense for
>>>>>> generic wide-int combinations (though then the issue is its operands
>>>>>> are no longer commutative which I think is the case with your wide-int
>>>>>> or double-int as well - they don't suport "1 + wide_int" for obvious
>>>>>> reasons).
>>>>>>
>>>>>> So there are implementation design choices left undecided.
>>>>>>
>>>>>> Oh, and the operation implementations are crap (they compute
>>>>>> nonsense).
>>>>>>
>>>>>> But you should get the idea.
>>>>>>
>>>>>> Richard.
>>>>>
>>>>>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-02 15:40                                                                           ` Richard Biener
  2013-04-02 19:23                                                                             ` Kenneth Zadeck
@ 2013-04-05 15:05                                                                             ` Kenneth Zadeck
  2013-04-08 13:06                                                                               ` Richard Biener
  1 sibling, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-05 15:05 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

Richard,

There has been something that has bothered me about you proposal for the 
storage manager and i think i can now characterize that problem.  Say i 
want to compute the expression

(a + b) / c

converting from tree values, using wide-int as the engine and then 
storing the result in a tree.   (A very common operation for the various 
simplifiers in gcc.)

in my version of wide-int where there is only the stack allocated fix 
size allocation for the data, the compiler arranges for 6 instances of 
wide-int that are "statically" allocated on the stack when the function 
is entered.    There would be 3 copies of the precision and data to get 
things started and one allocation variable sized object at the end when 
the INT_CST is built and one copy to put it back.   As i have argued, 
these copies are of negligible size.

In your world, to get things started, you would do 3 pointer copies to 
get the values out of the tree to set the expression leaves but then you 
will call the allocator 3 times to get space to hold the intermediate 
nodes before you get to pointer copy the result back into the result cst 
which still needs an allocation to build it. I am assuming that we can 
play the same game at the tree level that we do at the rtl level where 
we do 1 variable sized allocation to get the entire INT_CST rather than 
doing 1 fixed sized allocation and 1 variable sized one.

even if we take the simpler example of a + b, you still loose.   The 
cost of the extra allocation and it's subsequent recovery is more than 
my copies.   In fact, even in the simplest case of someone going from a 
HWI thru wide_int into tree, you have 2 allocations vs my 1.

I just do not see the cost savings and if there are no cost savings, you 
certainly cannot say that having these templates is simpler than not 
having the templates.

Kenny

On 04/02/2013 11:04 AM, Richard Biener wrote:
> On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> This patch contains a large number of the changes requested by Richi.   It
>> does not contain any of the changes that he requested to abstract the
>> storage layer.   That suggestion appears to be quite unworkable.
> I of course took this claim as a challenge ... with the following result.  It is
> of course quite workable ;)
>
> The attached patch implements the core wide-int class and three storage
> models (fixed size for things like plain HWI and double-int, variable size
> similar to how your wide-int works and an adaptor for the double-int as
> contained in trees).  With that you can now do
>
> HOST_WIDE_INT
> wi_test (tree x)
> {
>    // template argument deduction doesn't do the magic we want it to do
>    // to make this kind of implicit conversions work
>    // overload resolution considers this kind of conversions so we
>    // need some magic that combines both ... but seeding the overload
>    // set with some instantiations doesn't seem to be possible :/
>    // wide_int<> w = x + 1;
>    wide_int<> w;
>    w += x;
>    w += 1;
>    // template argument deduction doesn't deduce the return value type,
>    // not considering the template default argument either ...
>    // w = wi (x) + 1;
>    // we could support this by providing rvalue-to-lvalue promotion
>    // via a traits class?
>    // otoh it would lead to sub-optimal code anyway so we should
>    // make the result available as reference parameter and only support
>    // wide_int <> res; add (res, x, 1); ?
>    w = wi (x).operator+<wide_int<> >(1);
>    wide_int<>::add(w, x, 1);
>    return w.to_hwi ();
> }
>
> we are somewhat limited with C++ unless we want to get really fancy.
> Eventually providing operator+ just doesn't make much sense for
> generic wide-int combinations (though then the issue is its operands
> are no longer commutative which I think is the case with your wide-int
> or double-int as well - they don't suport "1 + wide_int" for obvious reasons).
>
> So there are implementation design choices left undecided.
>
> Oh, and the operation implementations are crap (they compute nonsense).
>
> But you should get the idea.
>
> Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Comments on the suggestion to use infinite precision math for wide int.
  2013-04-04 11:45                                                                                       ` Richard Biener
@ 2013-04-08  5:28                                                                                         ` Kenneth Zadeck
  2013-04-08 10:32                                                                                           ` Florian Weimer
  2013-04-08 13:12                                                                                           ` Richard Biener
  2013-04-22 21:39                                                                                         ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Richard Sandiford
  1 sibling, 2 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-08  5:28 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

Richard,

You advocate that I should be using an infinite precision
representation and I advocate a finite precision representation where
the precision is taken from the context.  I would like to make the
case for my position here, in a separate thread, because the other
thread is just getting too messy.

At both the tree level and the rtl level you have a type (mode is just
bad rep for types) and both of those explicitly have precisions. The
semantics of the programming languages that we implement define, or at
least recommend, that most operations be done in a precision that is
implementation dependent (or like java a particular machine
independent precision).  Each hardware platform specifies exactly how
every operation is done.  I will admit that infinite precision is more
esthetically pleasing than what i have done, but exact precision
matches the needs of these clients.  The problem is that the results
from infinite precision arithmetic differ in many significant ways
from finite precision math.  And the number of places where you have
to inject a precision to get the expected answer, ultimately makes the
infinite precision representation unattractive.

As I said on Thursday, whenever you do operations that do not satisfy
the requirements of a mathematical ring (add sub and mul are in a
ring, divide, shift and comparisons are not) you run the risk of
getting a result that is not what would have been obtained with either
a strict interpretation of the semantics or the machine. Intuitively
any operation that looks at the bits above the precision does not
qualify as an operation that works in a ring.

The poster child for operations that do not belong to a ring is division.
For my example, I am using 4 bit integers because it makes the
examples easy, but similar examples exist for any fixed precision.

Consider 8 * 10 / 4

in an infinite precision world the result is 20, but in a 4 bit
precision world the answer is 0.

another example is to ask if

-10 * 10 is less than 0?

again you get a different answer with infinite precision.   I would argue
that if i declare a variable of type uint32 and scale my examples i have
the right to expect the compiler to produce the same result as the
machine would.

While C and C++ may have enough wiggle room in their standards so that
this is just an unexpected, but legal, result as opposed to being wrong,
everyone will hate you (us) if we do this.  Furthermore, Java explicitly 
does
not allow this (not that anyone actually uses gcj).  I do not know
enough about go, ada and fortran to say how it would effect them.

In looking at the double-int class, the only operation that does not
fit in a ring that is done properly is shifting.  There we explicitly
pass in the precision.

The reason that we rarely see this kind of problem even though
double-int implements 128 bit infinite precision is that currently
very little of the compiler actually uses infinite precision in a
robust way.   In a large number of places, the code looks like:

if (TYPE_PRECISION (TREE_TYPE (...)) < HOST_BITS_PER_WIDE_INT)
    do something using inline operators.
else
    either do not do something or use const-double,

such code clears out most of these issues before the two passes that
embrace infinite precision get a chance to do much damage.  However,
my patch at the rtl level gets rid of most of this kind of code and
replaces it with calls to wide-int that currently uses only operations
within the precision.  I assume that if i went down the infinite
precision road at the tree level, that all of this would come to the
surface very quickly.  I prefer to not change my rep and not have to
deal with this later.

Add, subtract, multiply and the logicals are all safe.  But divide,
remainder, and all of the comparisons need explicit precisions.  In
addition operations like clz, ctl and clrsb need precisions.  In total
about half of the functions would need a precision passed in.  My
point is that once you have to start passing in the precision in for all
of those operations, it seems to be cleaner to get the precision from
the leaves of the tree as I currently do.

Once you buy into the math in a particular precision world, a lot of
the other issues that you raise are just settled.  Asking how to extend
a value beyond it's precision is like asking what the universe was like 
before
the big bang.  It is just something you do not need to know.

I understand that you would like to have functions like x + 1 work,
and so do I. I just could not figure out how to make them have
unsurprising semantics.  In particular, g++ did not seem to be happy
with me defining two plus operators, one for each of signed and
unsigned HWIs.  It seems like if someone explicitly added a wide_int
and an unsigned HWI that they had a right to have the unsigned hwi not
be sign extended.  But if you can show me how to do this, i am happy
to go down that road.

Kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08  5:28                                                                                         ` Comments on the suggestion to use infinite precision math for wide int Kenneth Zadeck
@ 2013-04-08 10:32                                                                                           ` Florian Weimer
  2013-04-08 13:58                                                                                             ` Kenneth Zadeck
  2013-04-08 13:12                                                                                           ` Richard Biener
  1 sibling, 1 reply; 217+ messages in thread
From: Florian Weimer @ 2013-04-08 10:32 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl,
	rdsandiford, Ian Lance Taylor

On 04/07/2013 07:16 PM, Kenneth Zadeck wrote:
> The poster child for operations that do not belong to a ring is division.
> For my example, I am using 4 bit integers because it makes the
> examples easy, but similar examples exist for any fixed precision.
>
> Consider 8 * 10 / 4
>
> in an infinite precision world the result is 20, but in a 4 bit
> precision world the answer is 0.

I think you mean "4" instead of "20".

> another example is to ask if
>
> -10 * 10 is less than 0?
>
> again you get a different answer with infinite precision.

Actually, for C/C++ ,you don't—because of undefined signed overflow
(at least with default compiler flags).  But similar examples with 
unsigned types exist, so this point isn't too relevant.

> I would argue
> that if i declare a variable of type uint32 and scale my examples i have
> the right to expect the compiler to produce the same result as the
> machine would.

In my very, very limited experience, the signed/unsigned mismatch is 
more confusing.  With infinite precision, this confusion would not arise 
(but adjustment would be needed to get limited-precision results, as you 
write).  With finite precision, you either need separate types for 
signed/unsigned, or separate operations.

> While C and C++ may have enough wiggle room in their standards so that
> this is just an unexpected, but legal, result as opposed to being wrong,
> everyone will hate you (us) if we do this.  Furthermore, Java explicitly
> does
> not allow this (not that anyone actually uses gcj).  I do not know
> enough about go,

Go specified two's-complement signed arithmetic and does not 
automatically promote to int (i.e., it performs arithmetic in the type, 
and mixed arguments are not supported).

Go constant arithmetic is infinite precision.

 > ada and fortran to say how it would effect them.

Ada requires trapping arithmetic for signed integers.  Currently, this 
is implemented in the front end.  Arithmetic happens in the base range 
of a type (which is symmetric around zero and chosen to correspond to a 
machine type).  Ada allows omitting intermediate overflow checks as long 
as you produce the infinite precision result (or raise an overflow 
exception).

I think this applies to Ada constant arithmetic as well.

(GNAT has a mode where comparisons are computed with infinite precision, 
which is extremely useful for writing bounds checking code.)

Considering the range of different arithmetic operations we need to 
support, I'm not convinced that the ring model is appropriate.

-- 
Florian Weimer / Red Hat Product Security Team

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-05 15:05                                                                             ` Kenneth Zadeck
@ 2013-04-08 13:06                                                                               ` Richard Biener
  2013-04-17  0:49                                                                                 ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-08 13:06 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On Fri, Apr 5, 2013 at 2:34 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> Richard,
>
> There has been something that has bothered me about you proposal for the
> storage manager and i think i can now characterize that problem.  Say i want
> to compute the expression
>
> (a + b) / c
>
> converting from tree values, using wide-int as the engine and then storing
> the result in a tree.   (A very common operation for the various simplifiers
> in gcc.)
>
> in my version of wide-int where there is only the stack allocated fix size
> allocation for the data, the compiler arranges for 6 instances of wide-int
> that are "statically" allocated on the stack when the function is entered.
> There would be 3 copies of the precision and data to get things started and
> one allocation variable sized object at the end when the INT_CST is built
> and one copy to put it back.   As i have argued, these copies are of
> negligible size.
>
> In your world, to get things started, you would do 3 pointer copies to get
> the values out of the tree to set the expression leaves but then you will
> call the allocator 3 times to get space to hold the intermediate nodes
> before you get to pointer copy the result back into the result cst which
> still needs an allocation to build it. I am assuming that we can play the
> same game at the tree level that we do at the rtl level where we do 1
> variable sized allocation to get the entire INT_CST rather than doing 1
> fixed sized allocation and 1 variable sized one.
>
> even if we take the simpler example of a + b, you still loose.   The cost of
> the extra allocation and it's subsequent recovery is more than my copies.
> In fact, even in the simplest case of someone going from a HWI thru wide_int
> into tree, you have 2 allocations vs my 1.

Just to clarify, my code wouldn't handle

  tree a, b, c;
  tree res = (a + b) / c;

transparently.  The most "complex" form of the above that I think would
be reasonable to handle would be

  tree a, b, c;
  wide_int wires = (wi (a) + b) / c;
  tree res = build_int_cst (TREE_TYPE (a), wires);

and the code as posted would even require you to specify the
return type of operator+ and operator/ explicitely like

 wide_int<> wires = (wi (a).operator+<wi_embed_var>
(b)).operator/<wi_embed_var> (c);

but as I said I just didn't bother to "decide" that the return type is
always of wide_int <variable-len-storage> kind.

Now, the only real allocation that happens is done by build_int_cst.
There is one wide_int on the stack to hold the a + b result and one
separate wide_int to hold wires (it's literally written in the code).
There are no "pointer copies" involved in the end - the result from
converting a tree to a wide_int<tree-storage> is the original 'tree'
pointer itself, thus a register.

> I just do not see the cost savings and if there are no cost savings, you
> certainly cannot say that having these templates is simpler than not having
> the templates.

I think you are missing the point - by abstracting away the storage
you don't necessarily need to add the templates.  But you open up
a very easy route for doing so and you make the operations _trivially_
work on the tree / RTL storage with no overhead in generated code
and minimal overhead in the amount of code in GCC itself.  In my
prototype the overhead of adding 'tree' support is to place

class wi_tree_int_cst
{
  tree cst;
public:
  void construct (tree c) { cst = c; }
  const HOST_WIDE_INT *storage() const { return reinterpret_cast
<HOST_WIDE_INT *>(&TREE_INT_CST (cst)); }
  unsigned len() const { return 2; }
};

template <>
class wi_traits <tree>
{
public:
    typedef wide_int <wi_tree_int_cst> wi_t;
    wi_traits(tree t)
  {
    wi_tree_int_cst ws;
    ws.construct (t);
    w.construct (ws);
  }
    wi_t* operator->() { return &w; }
private:
    wi_t w;
};

into tree.h.

Richard.

> Kenny
>
>
> On 04/02/2013 11:04 AM, Richard Biener wrote:
>>
>> On Wed, Feb 27, 2013 at 2:59 AM, Kenneth Zadeck
>> <zadeck@naturalbridge.com> wrote:
>>>
>>> This patch contains a large number of the changes requested by Richi.
>>> It
>>> does not contain any of the changes that he requested to abstract the
>>> storage layer.   That suggestion appears to be quite unworkable.
>>
>> I of course took this claim as a challenge ... with the following result.
>> It is
>> of course quite workable ;)
>>
>> The attached patch implements the core wide-int class and three storage
>> models (fixed size for things like plain HWI and double-int, variable size
>> similar to how your wide-int works and an adaptor for the double-int as
>> contained in trees).  With that you can now do
>>
>> HOST_WIDE_INT
>> wi_test (tree x)
>> {
>>    // template argument deduction doesn't do the magic we want it to do
>>    // to make this kind of implicit conversions work
>>    // overload resolution considers this kind of conversions so we
>>    // need some magic that combines both ... but seeding the overload
>>    // set with some instantiations doesn't seem to be possible :/
>>    // wide_int<> w = x + 1;
>>    wide_int<> w;
>>    w += x;
>>    w += 1;
>>    // template argument deduction doesn't deduce the return value type,
>>    // not considering the template default argument either ...
>>    // w = wi (x) + 1;
>>    // we could support this by providing rvalue-to-lvalue promotion
>>    // via a traits class?
>>    // otoh it would lead to sub-optimal code anyway so we should
>>    // make the result available as reference parameter and only support
>>    // wide_int <> res; add (res, x, 1); ?
>>    w = wi (x).operator+<wide_int<> >(1);
>>    wide_int<>::add(w, x, 1);
>>    return w.to_hwi ();
>> }
>>
>> we are somewhat limited with C++ unless we want to get really fancy.
>> Eventually providing operator+ just doesn't make much sense for
>> generic wide-int combinations (though then the issue is its operands
>> are no longer commutative which I think is the case with your wide-int
>> or double-int as well - they don't suport "1 + wide_int" for obvious
>> reasons).
>>
>> So there are implementation design choices left undecided.
>>
>> Oh, and the operation implementations are crap (they compute nonsense).
>>
>> But you should get the idea.
>>
>> Richard.
>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08  5:28                                                                                         ` Comments on the suggestion to use infinite precision math for wide int Kenneth Zadeck
  2013-04-08 10:32                                                                                           ` Florian Weimer
@ 2013-04-08 13:12                                                                                           ` Richard Biener
  2013-04-08 13:32                                                                                             ` Kenneth Zadeck
  2013-04-08 23:46                                                                                             ` Lawrence Crowl
  1 sibling, 2 replies; 217+ messages in thread
From: Richard Biener @ 2013-04-08 13:12 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On Sun, Apr 7, 2013 at 7:16 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> Richard,
>
> You advocate that I should be using an infinite precision
> representation and I advocate a finite precision representation where
> the precision is taken from the context.  I would like to make the
> case for my position here, in a separate thread, because the other
> thread is just getting too messy.
>
> At both the tree level and the rtl level you have a type (mode is just
> bad rep for types) and both of those explicitly have precisions. The
> semantics of the programming languages that we implement define, or at
> least recommend, that most operations be done in a precision that is
> implementation dependent (or like java a particular machine
> independent precision).  Each hardware platform specifies exactly how
> every operation is done.  I will admit that infinite precision is more
> esthetically pleasing than what i have done, but exact precision
> matches the needs of these clients.  The problem is that the results
> from infinite precision arithmetic differ in many significant ways
> from finite precision math.  And the number of places where you have
> to inject a precision to get the expected answer, ultimately makes the
> infinite precision representation unattractive.
>
> As I said on Thursday, whenever you do operations that do not satisfy
> the requirements of a mathematical ring (add sub and mul are in a
> ring, divide, shift and comparisons are not) you run the risk of
> getting a result that is not what would have been obtained with either
> a strict interpretation of the semantics or the machine. Intuitively
> any operation that looks at the bits above the precision does not
> qualify as an operation that works in a ring.
>
> The poster child for operations that do not belong to a ring is division.
> For my example, I am using 4 bit integers because it makes the
> examples easy, but similar examples exist for any fixed precision.
>
> Consider 8 * 10 / 4
>
> in an infinite precision world the result is 20, but in a 4 bit
> precision world the answer is 0.
>
> another example is to ask if
>
> -10 * 10 is less than 0?
>
> again you get a different answer with infinite precision.   I would argue
> that if i declare a variable of type uint32 and scale my examples i have
> the right to expect the compiler to produce the same result as the
> machine would.
>
> While C and C++ may have enough wiggle room in their standards so that
> this is just an unexpected, but legal, result as opposed to being wrong,
> everyone will hate you (us) if we do this.  Furthermore, Java explicitly
> does
> not allow this (not that anyone actually uses gcj).  I do not know
> enough about go, ada and fortran to say how it would effect them.
>
> In looking at the double-int class, the only operation that does not
> fit in a ring that is done properly is shifting.  There we explicitly
> pass in the precision.
>
> The reason that we rarely see this kind of problem even though
> double-int implements 128 bit infinite precision is that currently
> very little of the compiler actually uses infinite precision in a
> robust way.   In a large number of places, the code looks like:
>
> if (TYPE_PRECISION (TREE_TYPE (...)) < HOST_BITS_PER_WIDE_INT)
>    do something using inline operators.
> else
>    either do not do something or use const-double,
>
> such code clears out most of these issues before the two passes that
> embrace infinite precision get a chance to do much damage.  However,
> my patch at the rtl level gets rid of most of this kind of code and
> replaces it with calls to wide-int that currently uses only operations
> within the precision.  I assume that if i went down the infinite
> precision road at the tree level, that all of this would come to the
> surface very quickly.  I prefer to not change my rep and not have to
> deal with this later.
>
> Add, subtract, multiply and the logicals are all safe.  But divide,
> remainder, and all of the comparisons need explicit precisions.  In
> addition operations like clz, ctl and clrsb need precisions.  In total
> about half of the functions would need a precision passed in.  My
> point is that once you have to start passing in the precision in for all
> of those operations, it seems to be cleaner to get the precision from
> the leaves of the tree as I currently do.
>
> Once you buy into the math in a particular precision world, a lot of
> the other issues that you raise are just settled.  Asking how to extend
> a value beyond it's precision is like asking what the universe was like
> before
> the big bang.  It is just something you do not need to know.
>
> I understand that you would like to have functions like x + 1 work,
> and so do I. I just could not figure out how to make them have
> unsurprising semantics.  In particular, g++ did not seem to be happy
> with me defining two plus operators, one for each of signed and
> unsigned HWIs.  It seems like if someone explicitly added a wide_int
> and an unsigned HWI that they had a right to have the unsigned hwi not
> be sign extended.  But if you can show me how to do this, i am happy
> to go down that road.

I advocate the infinite precision signed representation as one solution
to avoid the issues that come up with your implementation (as I currently
have access to) which has a representation with N bits of precision
encoded with M <= N bits and no sign information.  That obviously
leaves operations on numbers of that representation with differing
N undefined.  You define it by having coded the operations which as far
as I can see simply assume N is equal for any two operands and
the effective sign for extending the M-bits encoding to the common
N-bits precision is "available".  A thorough specification of both
the encoding scheme and the operation semantics is missing.
I can side-step both of these issues nicely by simply using
a infinite precision signed representation and requiring the client to
explicitely truncate / extend to a specific precision when required.
I also leave open the possibility to have the _encoding_ be always
the same as an infinite precision signed representation but to always
require an explicitely specified target precision for each operation
(which rules out the use of operator overloading).

Citing your example:

  8 * 10 / 4

and transforming it slightly into a commonly used pattern:

  (byte-size * 8 + bit-size) / 8

then I argue that what people want here is this carried out in
_infinite_ precision!  Even if byte-size happens to come from
a sizetype TREE_INT_CST with 64bit precision.  So either
choice - having a fixed-precision representation or an
infinite-precision representation - can and will lead to errors
done by the programmer.  And as you can easily build a
finite precision wrapper around an infinite precision implementation
but not the other way around it's obvious to me what the
implementation should provide.

Richard.

> Kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 13:12                                                                                           ` Richard Biener
@ 2013-04-08 13:32                                                                                             ` Kenneth Zadeck
  2013-04-08 13:44                                                                                               ` Robert Dewar
                                                                                                                 ` (2 more replies)
  2013-04-08 23:46                                                                                             ` Lawrence Crowl
  1 sibling, 3 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-08 13:32 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor


On 04/08/2013 06:46 AM, Richard Biener wrote:
> On Sun, Apr 7, 2013 at 7:16 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> Richard,
>>
>> You advocate that I should be using an infinite precision
>> representation and I advocate a finite precision representation where
>> the precision is taken from the context.  I would like to make the
>> case for my position here, in a separate thread, because the other
>> thread is just getting too messy.
>>
>> At both the tree level and the rtl level you have a type (mode is just
>> bad rep for types) and both of those explicitly have precisions. The
>> semantics of the programming languages that we implement define, or at
>> least recommend, that most operations be done in a precision that is
>> implementation dependent (or like java a particular machine
>> independent precision).  Each hardware platform specifies exactly how
>> every operation is done.  I will admit that infinite precision is more
>> esthetically pleasing than what i have done, but exact precision
>> matches the needs of these clients.  The problem is that the results
>> from infinite precision arithmetic differ in many significant ways
>> from finite precision math.  And the number of places where you have
>> to inject a precision to get the expected answer, ultimately makes the
>> infinite precision representation unattractive.
>>
>> As I said on Thursday, whenever you do operations that do not satisfy
>> the requirements of a mathematical ring (add sub and mul are in a
>> ring, divide, shift and comparisons are not) you run the risk of
>> getting a result that is not what would have been obtained with either
>> a strict interpretation of the semantics or the machine. Intuitively
>> any operation that looks at the bits above the precision does not
>> qualify as an operation that works in a ring.
>>
>> The poster child for operations that do not belong to a ring is division.
>> For my example, I am using 4 bit integers because it makes the
>> examples easy, but similar examples exist for any fixed precision.
>>
>> Consider 8 * 10 / 4
>>
>> in an infinite precision world the result is 20, but in a 4 bit
>> precision world the answer is 0.
>>
>> another example is to ask if
>>
>> -10 * 10 is less than 0?
>>
>> again you get a different answer with infinite precision.   I would argue
>> that if i declare a variable of type uint32 and scale my examples i have
>> the right to expect the compiler to produce the same result as the
>> machine would.
>>
>> While C and C++ may have enough wiggle room in their standards so that
>> this is just an unexpected, but legal, result as opposed to being wrong,
>> everyone will hate you (us) if we do this.  Furthermore, Java explicitly
>> does
>> not allow this (not that anyone actually uses gcj).  I do not know
>> enough about go, ada and fortran to say how it would effect them.
>>
>> In looking at the double-int class, the only operation that does not
>> fit in a ring that is done properly is shifting.  There we explicitly
>> pass in the precision.
>>
>> The reason that we rarely see this kind of problem even though
>> double-int implements 128 bit infinite precision is that currently
>> very little of the compiler actually uses infinite precision in a
>> robust way.   In a large number of places, the code looks like:
>>
>> if (TYPE_PRECISION (TREE_TYPE (...)) < HOST_BITS_PER_WIDE_INT)
>>     do something using inline operators.
>> else
>>     either do not do something or use const-double,
>>
>> such code clears out most of these issues before the two passes that
>> embrace infinite precision get a chance to do much damage.  However,
>> my patch at the rtl level gets rid of most of this kind of code and
>> replaces it with calls to wide-int that currently uses only operations
>> within the precision.  I assume that if i went down the infinite
>> precision road at the tree level, that all of this would come to the
>> surface very quickly.  I prefer to not change my rep and not have to
>> deal with this later.
>>
>> Add, subtract, multiply and the logicals are all safe.  But divide,
>> remainder, and all of the comparisons need explicit precisions.  In
>> addition operations like clz, ctl and clrsb need precisions.  In total
>> about half of the functions would need a precision passed in.  My
>> point is that once you have to start passing in the precision in for all
>> of those operations, it seems to be cleaner to get the precision from
>> the leaves of the tree as I currently do.
>>
>> Once you buy into the math in a particular precision world, a lot of
>> the other issues that you raise are just settled.  Asking how to extend
>> a value beyond it's precision is like asking what the universe was like
>> before
>> the big bang.  It is just something you do not need to know.
>>
>> I understand that you would like to have functions like x + 1 work,
>> and so do I. I just could not figure out how to make them have
>> unsurprising semantics.  In particular, g++ did not seem to be happy
>> with me defining two plus operators, one for each of signed and
>> unsigned HWIs.  It seems like if someone explicitly added a wide_int
>> and an unsigned HWI that they had a right to have the unsigned hwi not
>> be sign extended.  But if you can show me how to do this, i am happy
>> to go down that road.
> I advocate the infinite precision signed representation as one solution
> to avoid the issues that come up with your implementation (as I currently
> have access to) which has a representation with N bits of precision
> encoded with M <= N bits and no sign information.  That obviously
> leaves operations on numbers of that representation with differing
> N undefined.  You define it by having coded the operations which as far
> as I can see simply assume N is equal for any two operands and
> the effective sign for extending the M-bits encoding to the common
> N-bits precision is "available".  A thorough specification of both
> the encoding scheme and the operation semantics is missing.
This is a perfectly reasonable request.
> I can side-step both of these issues nicely by simply using
> a infinite precision signed representation and requiring the client to
> explicitely truncate / extend to a specific precision when required.
> I also leave open the possibility to have the _encoding_ be always
> the same as an infinite precision signed representation but to always
> require an explicitely specified target precision for each operation
> (which rules out the use of operator overloading).
>
> Citing your example:
>
>    8 * 10 / 4
>
> and transforming it slightly into a commonly used pattern:
>
>    (byte-size * 8 + bit-size) / 8
Patterns like this are generally not encoded in either double int or 
wide-int.   I do not think that anyone has taken the position that all 
math be done in a wide math, only the math on the variables that appear 
in the programs.


> then I argue that what people want here is this carried out in
> _infinite_ precision!  Even if byte-size happens to come from
> a sizetype TREE_INT_CST with 64bit precision.  So either
> choice - having a fixed-precision representation or an
> infinite-precision representation - can and will lead to errors
> done by the programmer.  And as you can easily build a
> finite precision wrapper around an infinite precision implementation
> but not the other way around it's obvious to me what the
> implementation should provide.
>
> Richard.
Infinite precision does get rid of the issue that you have to specify 
the precision at the leaves.    However, for the vast majority 
expression trees that get built, the leaves already have their precision 
in the type or the mode.   On the other hand to keep the math sane, the 
infinite precision requires either external truncation (ugly) or 
specification of the precision and many interior nodes of the expression 
tree (just as ugly as my putting it at the constant leaves).

The other problem, which i invite you to use the full power of your c++ 
sorcery on, is the one where defining an operator so that wide-int + 
unsigned hwi is either rejected or properly zero extended.    If you can 
do this, I will go along with your suggestion that the internal rep 
should be sign extended.  Saying that constants are always sign extended 
seems ok, but there are a huge number of places where we convert 
unsigned hwis as the second operand and i do not want that to be a 
trap.  I went thru a round of this, where i did not post the patch 
because i could not make this work.   And the number of places where you 
want to use an hwi as the second operand dwarfs the number of places 
where you want to use a small integer constant.
>> Kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 13:32                                                                                             ` Kenneth Zadeck
@ 2013-04-08 13:44                                                                                               ` Robert Dewar
  2013-04-08 14:26                                                                                                 ` Kenneth Zadeck
  2013-04-08 19:06                                                                                               ` Richard Biener
  2013-04-08 22:34                                                                                               ` Lawrence Crowl
  2 siblings, 1 reply; 217+ messages in thread
From: Robert Dewar @ 2013-04-08 13:44 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl,
	rdsandiford, Ian Lance Taylor

It may be interesting to look at what we have done in
Ada with regard to overflow in intermediate expressions.
Briefly we allow specification of three modes

all intermediate arithmetic is done in the base type,
with overflow signalled if an intermediate value is
outside this range.

all intermediate arithmetic is done in the widest
integer type, with overflow signalled if an intermediate
value is outside this range.

all intermediate arithmetic uses an infinite precision
arithmetic package built for this purpose.

In the second and third cases we do range analysis that
allows smaller intermediate precision if we know it's
safe.

We also allow separate specification of the mode inside
and outside assertions (e.g. preconditions and postconditions)
since in the latter you often want to regard integers as
mathematical, not subject to intermediate overflow.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 10:32                                                                                           ` Florian Weimer
@ 2013-04-08 13:58                                                                                             ` Kenneth Zadeck
  2013-04-08 14:00                                                                                               ` Robert Dewar
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-08 13:58 UTC (permalink / raw)
  To: Florian Weimer
  Cc: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl,
	rdsandiford, Ian Lance Taylor

On 04/08/2013 04:56 AM, Florian Weimer wrote:
> On 04/07/2013 07:16 PM, Kenneth Zadeck wrote:
>> The poster child for operations that do not belong to a ring is 
>> division.
>> For my example, I am using 4 bit integers because it makes the
>> examples easy, but similar examples exist for any fixed precision.
>>
>> Consider 8 * 10 / 4
>>
>> in an infinite precision world the result is 20, but in a 4 bit
>> precision world the answer is 0.
>
> I think you mean "4" instead of "20".
>
oops
>> another example is to ask if
>>
>> -10 * 10 is less than 0?
>>
>> again you get a different answer with infinite precision.
>
> Actually, for C/C++ ,you don't—because of undefined signed overflow
> (at least with default compiler flags).  But similar examples with 
> unsigned types exist, so this point isn't too relevant.
>
>> I would argue
>> that if i declare a variable of type uint32 and scale my examples i have
>> the right to expect the compiler to produce the same result as the
>> machine would.
>
> In my very, very limited experience, the signed/unsigned mismatch is 
> more confusing.  With infinite precision, this confusion would not 
> arise (but adjustment would be needed to get limited-precision 
> results, as you write).  With finite precision, you either need 
> separate types for signed/unsigned, or separate operations.
>
I come from a world where people write code where they expect full 
control of the horizon and vertical when they program.   Hank Warren, 
the author of Hacker Delight is in my group and a huge number of those 
tricks require understanding what is going on in the machine.  If the 
compiler decides that it wants to do things differently, you are dead.
>> While C and C++ may have enough wiggle room in their standards so that
>> this is just an unexpected, but legal, result as opposed to being wrong,
>> everyone will hate you (us) if we do this.  Furthermore, Java explicitly
>> does
>> not allow this (not that anyone actually uses gcj).  I do not know
>> enough about go,
>
> Go specified two's-complement signed arithmetic and does not 
> automatically promote to int (i.e., it performs arithmetic in the 
> type, and mixed arguments are not supported).
>
> Go constant arithmetic is infinite precision.
>
> > ada and fortran to say how it would effect them.
>
> Ada requires trapping arithmetic for signed integers.  Currently, this 
> is implemented in the front end.  Arithmetic happens in the base range 
> of a type (which is symmetric around zero and chosen to correspond to 
> a machine type).  Ada allows omitting intermediate overflow checks as 
> long as you produce the infinite precision result (or raise an 
> overflow exception).
>
> I think this applies to Ada constant arithmetic as well.
>
> (GNAT has a mode where comparisons are computed with infinite 
> precision, which is extremely useful for writing bounds checking code.)
>
> Considering the range of different arithmetic operations we need to 
> support, I'm not convinced that the ring model is appropriate.
>
I will answer this in Robert's email.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 13:58                                                                                             ` Kenneth Zadeck
@ 2013-04-08 14:00                                                                                               ` Robert Dewar
  2013-04-08 14:12                                                                                                 ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Robert Dewar @ 2013-04-08 14:00 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Florian Weimer, Richard Biener, Mike Stump, gcc-patches,
	Lawrence Crowl, rdsandiford, Ian Lance Taylor

On 4/8/2013 9:15 AM, Kenneth Zadeck wrote:

>> I think this applies to Ada constant arithmetic as well.

Ada constant arithmetic (at compile time) is always infinite
precision (for float as well as for integer).

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 14:00                                                                                               ` Robert Dewar
@ 2013-04-08 14:12                                                                                                 ` Kenneth Zadeck
  2013-04-08 14:41                                                                                                   ` Robert Dewar
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-08 14:12 UTC (permalink / raw)
  To: Robert Dewar
  Cc: Florian Weimer, Richard Biener, Mike Stump, gcc-patches,
	Lawrence Crowl, rdsandiford, Ian Lance Taylor

On 04/08/2013 09:19 AM, Robert Dewar wrote:
> On 4/8/2013 9:15 AM, Kenneth Zadeck wrote:
>
>>> I think this applies to Ada constant arithmetic as well.
>
> Ada constant arithmetic (at compile time) is always infinite
> precision (for float as well as for integer).
>
What do you mean when you say "constant arithmetic"?    Do you mean 
places where there is an explicit 8 * 6 in the source or do you mean any 
arithmetic that a compiler, using the full power of interprocedural 
constant propagation can discover?

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 13:44                                                                                               ` Robert Dewar
@ 2013-04-08 14:26                                                                                                 ` Kenneth Zadeck
  2013-04-08 14:35                                                                                                   ` Robert Dewar
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-08 14:26 UTC (permalink / raw)
  To: Robert Dewar
  Cc: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl,
	rdsandiford, Ian Lance Taylor

On 04/08/2013 09:03 AM, Robert Dewar wrote:
> It may be interesting to look at what we have done in
> Ada with regard to overflow in intermediate expressions.
> Briefly we allow specification of three modes
>
> all intermediate arithmetic is done in the base type,
> with overflow signalled if an intermediate value is
> outside this range.
>
> all intermediate arithmetic is done in the widest
> integer type, with overflow signalled if an intermediate
> value is outside this range.
>
> all intermediate arithmetic uses an infinite precision
> arithmetic package built for this purpose.
>
> In the second and third cases we do range analysis that
> allows smaller intermediate precision if we know it's
> safe.
>
> We also allow separate specification of the mode inside
> and outside assertions (e.g. preconditions and postconditions)
> since in the latter you often want to regard integers as
> mathematical, not subject to intermediate overflow.
So then how does a language like ada work in gcc?   My assumption is 
that most of what you describe here is done in the front end and by the 
time you get to the middle end of the compiler, you have chosen types 
for which you are comfortable to have any remaining math done in along 
with explicit checks for overflow where the programmer asked for them.

Otherwise, how could ada have ever worked with gcc?

kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 14:26                                                                                                 ` Kenneth Zadeck
@ 2013-04-08 14:35                                                                                                   ` Robert Dewar
  0 siblings, 0 replies; 217+ messages in thread
From: Robert Dewar @ 2013-04-08 14:35 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl,
	rdsandiford, Ian Lance Taylor

On 4/8/2013 9:24 AM, Kenneth Zadeck wrote:

> So then how does a language like ada work in gcc?   My assumption is
> that most of what you describe here is done in the front end and by the
> time you get to the middle end of the compiler, you have chosen types
> for which you are comfortable to have any remaining math done in along
> with explicit checks for overflow where the programmer asked for them.

That's right, the front end does all the promotion of types
>
> Otherwise, how could ada have ever worked with gcc?

Sometimes we do have to make changes to gcc to accomodate Ada
specific requirements, but this was not one of those cases. Of
course the back end would do a better job of the range analysis
to remove some unnecessary use of infinite precision, but the
front end in practice does a good enough job.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 14:12                                                                                                 ` Kenneth Zadeck
@ 2013-04-08 14:41                                                                                                   ` Robert Dewar
  2013-04-08 15:10                                                                                                     ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Robert Dewar @ 2013-04-08 14:41 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Florian Weimer, Richard Biener, Mike Stump, gcc-patches,
	Lawrence Crowl, rdsandiford, Ian Lance Taylor

On 4/8/2013 9:23 AM, Kenneth Zadeck wrote:
> On 04/08/2013 09:19 AM, Robert Dewar wrote:
>> On 4/8/2013 9:15 AM, Kenneth Zadeck wrote:
>>
>>>> I think this applies to Ada constant arithmetic as well.
>>
>> Ada constant arithmetic (at compile time) is always infinite
>> precision (for float as well as for integer).
>>
> What do you mean when you say "constant arithmetic"?    Do you mean
> places where there is an explicit 8 * 6 in the source or do you mean any
> arithmetic that a compiler, using the full power of interprocedural
> constant propagation can discover?

Somewhere between the two. Ada has a very well defined notion of
what is and what is not a "static expression", it definitely does not
include everything the compiler can discover, but it goes beyond just
explicit literal arithmetic, e.g. declared constants

    X : Integer := 75;

are considered static. It is static expressions that must be computed
with full precision at compile time. For expressions the compiler can
tell are constant even though not officially static, it is fine to
compute at compile time for integer, but NOT for float, since you want
to use target precision for all non-static float-operations.
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 14:41                                                                                                   ` Robert Dewar
@ 2013-04-08 15:10                                                                                                     ` Kenneth Zadeck
  2013-04-08 17:18                                                                                                       ` Robert Dewar
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-08 15:10 UTC (permalink / raw)
  To: Robert Dewar
  Cc: Florian Weimer, Richard Biener, Mike Stump, gcc-patches,
	Lawrence Crowl, rdsandiford, Ian Lance Taylor

On 04/08/2013 09:52 AM, Robert Dewar wrote:
> On 4/8/2013 9:23 AM, Kenneth Zadeck wrote:
>> On 04/08/2013 09:19 AM, Robert Dewar wrote:
>>> On 4/8/2013 9:15 AM, Kenneth Zadeck wrote:
>>>
>>>>> I think this applies to Ada constant arithmetic as well.
>>>
>>> Ada constant arithmetic (at compile time) is always infinite
>>> precision (for float as well as for integer).
>>>
>> What do you mean when you say "constant arithmetic"?    Do you mean
>> places where there is an explicit 8 * 6 in the source or do you mean any
>> arithmetic that a compiler, using the full power of interprocedural
>> constant propagation can discover?
>
> Somewhere between the two. Ada has a very well defined notion of
> what is and what is not a "static expression", it definitely does not
> include everything the compiler can discover, but it goes beyond just
> explicit literal arithmetic, e.g. declared constants
>
>    X : Integer := 75;
>
I actually guessed that it was something like this but i did not want to 
spend the time trying to figure this bit of ada syntax out.
> are considered static. It is static expressions that must be computed
> with full precision at compile time. For expressions the compiler can
> tell are constant even though not officially static, it is fine to
> compute at compile time for integer, but NOT for float, since you want
> to use target precision for all non-static float-operations.
>>
>
yes but the relevant question for the not officially static integer 
constants is "in what precision are those operations to be performed 
in?    I assume that you choose gcc types for these operations and you 
expect the math to be done within that type, i.e. exactly the way you 
expect the machine to perform.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 15:10                                                                                                     ` Kenneth Zadeck
@ 2013-04-08 17:18                                                                                                       ` Robert Dewar
  2013-04-08 17:22                                                                                                         ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Robert Dewar @ 2013-04-08 17:18 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Florian Weimer, Richard Biener, Mike Stump, gcc-patches,
	Lawrence Crowl, rdsandiford, Ian Lance Taylor

On 4/8/2013 9:58 AM, Kenneth Zadeck wrote:

> yes but the relevant question for the not officially static integer
> constants is "in what precision are those operations to be performed
> in?    I assume that you choose gcc types for these operations and you
> expect the math to be done within that type, i.e. exactly the way you
> expect the machine to perform.

As I explained in an earlier message, *within* a single expression, we
are free to use higher precision, and we provide modes that allow this
up to and including the usea of infinite precision. That applies not
just to constant expressions but to all expressions.
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 17:18                                                                                                       ` Robert Dewar
@ 2013-04-08 17:22                                                                                                         ` Kenneth Zadeck
  2013-04-08 19:14                                                                                                           ` Robert Dewar
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-08 17:22 UTC (permalink / raw)
  To: Robert Dewar
  Cc: Florian Weimer, Richard Biener, Mike Stump, gcc-patches,
	Lawrence Crowl, rdsandiford, Ian Lance Taylor

On 04/08/2013 10:12 AM, Robert Dewar wrote:
> On 4/8/2013 9:58 AM, Kenneth Zadeck wrote:
>
>> yes but the relevant question for the not officially static integer
>> constants is "in what precision are those operations to be performed
>> in?    I assume that you choose gcc types for these operations and you
>> expect the math to be done within that type, i.e. exactly the way you
>> expect the machine to perform.
>
> As I explained in an earlier message, *within* a single expression, we
> are free to use higher precision, and we provide modes that allow this
> up to and including the usea of infinite precision. That applies not
> just to constant expressions but to all expressions.
>>
>
My confusion is what you mean by "we"?   Do you mean "we" the writer of 
the program, "we" the person invoking the compiler by the use command 
line options or "we", your company's implementation of ada?

My interpretation of your first email was that it was possible for the 
programmer to do something equivalent to adding attributes surrounding a 
block in the program to control the precision and overflow detection of 
the expressions in the block.   And if this is so, then by the time the 
expression is seen by the middle end of gcc, those attributes will have 
been converted into tree code will evaluate the code in a well defined 
way by both the optimization passes and the target machine.

Kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 13:32                                                                                             ` Kenneth Zadeck
  2013-04-08 13:44                                                                                               ` Robert Dewar
@ 2013-04-08 19:06                                                                                               ` Richard Biener
  2013-04-08 22:34                                                                                               ` Lawrence Crowl
  2 siblings, 0 replies; 217+ messages in thread
From: Richard Biener @ 2013-04-08 19:06 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On Mon, Apr 8, 2013 at 2:43 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>
> On 04/08/2013 06:46 AM, Richard Biener wrote:
>>
>> On Sun, Apr 7, 2013 at 7:16 PM, Kenneth Zadeck <zadeck@naturalbridge.com>
>> wrote:
>>>
>>> Richard,
>>>
>>> You advocate that I should be using an infinite precision
>>> representation and I advocate a finite precision representation where
>>> the precision is taken from the context.  I would like to make the
>>> case for my position here, in a separate thread, because the other
>>> thread is just getting too messy.
>>>
>>> At both the tree level and the rtl level you have a type (mode is just
>>> bad rep for types) and both of those explicitly have precisions. The
>>> semantics of the programming languages that we implement define, or at
>>> least recommend, that most operations be done in a precision that is
>>> implementation dependent (or like java a particular machine
>>> independent precision).  Each hardware platform specifies exactly how
>>> every operation is done.  I will admit that infinite precision is more
>>> esthetically pleasing than what i have done, but exact precision
>>> matches the needs of these clients.  The problem is that the results
>>> from infinite precision arithmetic differ in many significant ways
>>> from finite precision math.  And the number of places where you have
>>> to inject a precision to get the expected answer, ultimately makes the
>>> infinite precision representation unattractive.
>>>
>>> As I said on Thursday, whenever you do operations that do not satisfy
>>> the requirements of a mathematical ring (add sub and mul are in a
>>> ring, divide, shift and comparisons are not) you run the risk of
>>> getting a result that is not what would have been obtained with either
>>> a strict interpretation of the semantics or the machine. Intuitively
>>> any operation that looks at the bits above the precision does not
>>> qualify as an operation that works in a ring.
>>>
>>> The poster child for operations that do not belong to a ring is division.
>>> For my example, I am using 4 bit integers because it makes the
>>> examples easy, but similar examples exist for any fixed precision.
>>>
>>> Consider 8 * 10 / 4
>>>
>>> in an infinite precision world the result is 20, but in a 4 bit
>>> precision world the answer is 0.
>>>
>>> another example is to ask if
>>>
>>> -10 * 10 is less than 0?
>>>
>>> again you get a different answer with infinite precision.   I would argue
>>> that if i declare a variable of type uint32 and scale my examples i have
>>> the right to expect the compiler to produce the same result as the
>>> machine would.
>>>
>>> While C and C++ may have enough wiggle room in their standards so that
>>> this is just an unexpected, but legal, result as opposed to being wrong,
>>> everyone will hate you (us) if we do this.  Furthermore, Java explicitly
>>> does
>>> not allow this (not that anyone actually uses gcj).  I do not know
>>> enough about go, ada and fortran to say how it would effect them.
>>>
>>> In looking at the double-int class, the only operation that does not
>>> fit in a ring that is done properly is shifting.  There we explicitly
>>> pass in the precision.
>>>
>>> The reason that we rarely see this kind of problem even though
>>> double-int implements 128 bit infinite precision is that currently
>>> very little of the compiler actually uses infinite precision in a
>>> robust way.   In a large number of places, the code looks like:
>>>
>>> if (TYPE_PRECISION (TREE_TYPE (...)) < HOST_BITS_PER_WIDE_INT)
>>>     do something using inline operators.
>>> else
>>>     either do not do something or use const-double,
>>>
>>> such code clears out most of these issues before the two passes that
>>> embrace infinite precision get a chance to do much damage.  However,
>>> my patch at the rtl level gets rid of most of this kind of code and
>>> replaces it with calls to wide-int that currently uses only operations
>>> within the precision.  I assume that if i went down the infinite
>>> precision road at the tree level, that all of this would come to the
>>> surface very quickly.  I prefer to not change my rep and not have to
>>> deal with this later.
>>>
>>> Add, subtract, multiply and the logicals are all safe.  But divide,
>>> remainder, and all of the comparisons need explicit precisions.  In
>>> addition operations like clz, ctl and clrsb need precisions.  In total
>>> about half of the functions would need a precision passed in.  My
>>> point is that once you have to start passing in the precision in for all
>>> of those operations, it seems to be cleaner to get the precision from
>>> the leaves of the tree as I currently do.
>>>
>>> Once you buy into the math in a particular precision world, a lot of
>>> the other issues that you raise are just settled.  Asking how to extend
>>> a value beyond it's precision is like asking what the universe was like
>>> before
>>> the big bang.  It is just something you do not need to know.
>>>
>>> I understand that you would like to have functions like x + 1 work,
>>> and so do I. I just could not figure out how to make them have
>>> unsurprising semantics.  In particular, g++ did not seem to be happy
>>> with me defining two plus operators, one for each of signed and
>>> unsigned HWIs.  It seems like if someone explicitly added a wide_int
>>> and an unsigned HWI that they had a right to have the unsigned hwi not
>>> be sign extended.  But if you can show me how to do this, i am happy
>>> to go down that road.
>>
>> I advocate the infinite precision signed representation as one solution
>> to avoid the issues that come up with your implementation (as I currently
>> have access to) which has a representation with N bits of precision
>> encoded with M <= N bits and no sign information.  That obviously
>> leaves operations on numbers of that representation with differing
>> N undefined.  You define it by having coded the operations which as far
>> as I can see simply assume N is equal for any two operands and
>> the effective sign for extending the M-bits encoding to the common
>> N-bits precision is "available".  A thorough specification of both
>> the encoding scheme and the operation semantics is missing.
>
> This is a perfectly reasonable request.
>
>> I can side-step both of these issues nicely by simply using
>> a infinite precision signed representation and requiring the client to
>> explicitely truncate / extend to a specific precision when required.
>> I also leave open the possibility to have the _encoding_ be always
>> the same as an infinite precision signed representation but to always
>> require an explicitely specified target precision for each operation
>> (which rules out the use of operator overloading).
>>
>> Citing your example:
>>
>>    8 * 10 / 4
>>
>> and transforming it slightly into a commonly used pattern:
>>
>>    (byte-size * 8 + bit-size) / 8
>
> Patterns like this are generally not encoded in either double int or
> wide-int.   I do not think that anyone has taken the position that all math
> be done in a wide math, only the math on the variables that appear in the
> programs.

Especially sizetype arithmetic - which appears in programs - is generally
done in double_int _exactly_ to cater for the above issue.  And that
assumes (usually without checking) that a double-int can encode
sizeof(size_t) * 8 + 3 bits in precision.  Which would not be true for
a 32bit HWI host and a 64bit target (which is why we have need_hwint64).

>> then I argue that what people want here is this carried out in
>> _infinite_ precision!  Even if byte-size happens to come from
>> a sizetype TREE_INT_CST with 64bit precision.  So either
>> choice - having a fixed-precision representation or an
>> infinite-precision representation - can and will lead to errors
>> done by the programmer.  And as you can easily build a
>> finite precision wrapper around an infinite precision implementation
>> but not the other way around it's obvious to me what the
>> implementation should provide.
>>
>> Richard.
>
> Infinite precision does get rid of the issue that you have to specify the
> precision at the leaves.    However, for the vast majority expression trees
> that get built, the leaves already have their precision in the type or the
> mode.   On the other hand to keep the math sane, the infinite precision
> requires either external truncation (ugly) or specification of the precision
> and many interior nodes of the expression tree (just as ugly as my putting
> it at the constant leaves).

Indeed the only "pretty" operation is with fully infinite precision computes.
But as you most of the time have a single operation per stmt performing
one truncation/extension for the result isn't that bad.  And only supporting
explicit truncation/extension is the 2nd most "pretty" option.  Certainly
the need to provide a precision when constructing wide_int::one () isn't
pretty either ...

> The other problem, which i invite you to use the full power of your c++
> sorcery on, is the one where defining an operator so that wide-int +
> unsigned hwi is either rejected or properly zero extended.    If you can do
> this, I will go along with your suggestion that the internal rep should be
> sign extended.

That's very easy with template specialization (not with overloading as
you might have figured out).

typdef signed long HOST_WIDE_INT;
template <typename T>
struct to_shwi
{
  void to_shwi (HOST_WIDE_INT *s, HOST_WIDE_INT x)
    { s[0] = x; }
};

template <>
struct to_shwi<unsigned HOST_WIDE_INT>
{
  void to_shwi (HOST_WIDE_INT *s, unsigned HOST_WIDE_INT x)
    { s[0] = x; s[1] = 0; }
};

gives a method to properly initialize the sign-extended HWI representation
from any integer type.  Needs additional specializations if init from
long long is suported and long long is bigger than HOST_WIDE_INT.

That is, I suppose your issue was stuff like

   wide_int operator+(unsigned HOST_WIDE_INT);
   wide_int operator+(HOST_WIDE_INT);

then you'd write that as

   template <class T>
   wide_int operator+(T);

and in the implementation use the to_swhi class (or a class providing
exactly what you need) that is specialized for the unsigned HOST_WIDE_INT
case (smaller operands automatically are promoted in the right way to
signed HOST_WIDE_INT).

>  Saying that constants are always sign extended seems ok, but
> there are a huge number of places where we convert unsigned hwis as the
> second operand and i do not want that to be a trap.  I went thru a round of
> this, where i did not post the patch because i could not make this work.
> And the number of places where you want to use an hwi as the second operand
> dwarfs the number of places where you want to use a small integer constant.

See above - this isn't an issue if you use templates for the "overloads".

Richard.

>>>
>>> Kenny
>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 17:22                                                                                                         ` Kenneth Zadeck
@ 2013-04-08 19:14                                                                                                           ` Robert Dewar
  2013-04-08 23:48                                                                                                             ` Lawrence Crowl
  0 siblings, 1 reply; 217+ messages in thread
From: Robert Dewar @ 2013-04-08 19:14 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Florian Weimer, Richard Biener, Mike Stump, gcc-patches,
	Lawrence Crowl, rdsandiford, Ian Lance Taylor

On 4/8/2013 10:26 AM, Kenneth Zadeck wrote:

> My confusion is what you mean by "we"?   Do you mean "we" the writer of
> the program, "we" the person invoking the compiler by the use command
> line options or "we", your company's implementation of ada?

Sorry, bad usage, The gcc implementation of Ada allows the user to
specify by pragmas how intermediate overflow is handled.
>
> My interpretation of your first email was that it was possible for the
> programmer to do something equivalent to adding attributes surrounding a
> block in the program to control the precision and overflow detection of
> the expressions in the block.   And if this is so, then by the time the
> expression is seen by the middle end of gcc, those attributes will have
> been converted into tree code will evaluate the code in a well defined
> way by both the optimization passes and the target machine.

Yes, that's a correct understanding
>
> Kenny
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 13:32                                                                                             ` Kenneth Zadeck
  2013-04-08 13:44                                                                                               ` Robert Dewar
  2013-04-08 19:06                                                                                               ` Richard Biener
@ 2013-04-08 22:34                                                                                               ` Lawrence Crowl
  2013-04-09  9:47                                                                                                 ` Richard Biener
  2 siblings, 1 reply; 217+ messages in thread
From: Lawrence Crowl @ 2013-04-08 22:34 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Richard Biener, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

On 4/8/13, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> The other problem, which i invite you to use the full power of
> your c++ sorcery on, is the one where defining an operator so
> that wide-int + unsigned hwi is either rejected or properly
> zero extended.  If you can do this, I will go along with
> your suggestion that the internal rep should be sign extended.
> Saying that constants are always sign extended seems ok, but there
> are a huge number of places where we convert unsigned hwis as
> the second operand and i do not want that to be a trap.  I went
> thru a round of this, where i did not post the patch because i
> could not make this work.  And the number of places where you
> want to use an hwi as the second operand dwarfs the number of
> places where you want to use a small integer constant.

You can use overloading, as in the following, which actually ignores
handling the sign in the representation.

class number {
        unsigned int rep1;
        int representation;
public:
        number(int arg) : representation(arg) {}
        number(unsigned int arg) : representation(arg) {}
        friend number operator+(number, int);
        friend number operator+(number, unsigned int);
        friend number operator+(int, number);
        friend number operator+(unsigned int, number);
};

number operator+(number n, int si) {
    return n.representation + si;
}

number operator+(number n, unsigned int ui) {
    return n.representation + ui;
}

number operator+(int si, number n) {
    return n.representation + si;
}

number operator+(unsigned int ui, number n) {
    return n.representation + ui;
}

If the argument type is of a template type parameter, then
you can test the template type via

    if (std::is_signed<T>::value)
      .... // sign extend
    else
      .... // zero extend

See http://www.cplusplus.com/reference/type_traits/is_signed/.

If you want to handle non-builtin types that are asigne dor unsigned,
then you need to add a specialization for is_signed.

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 13:12                                                                                           ` Richard Biener
  2013-04-08 13:32                                                                                             ` Kenneth Zadeck
@ 2013-04-08 23:46                                                                                             ` Lawrence Crowl
  1 sibling, 0 replies; 217+ messages in thread
From: Lawrence Crowl @ 2013-04-08 23:46 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

On 4/8/13, Richard Biener <richard.guenther@gmail.com> wrote:
> I advocate the infinite precision signed representation as one
> solution to avoid the issues that come up with your implementation
> (as I currently have access to) which has a representation
> with N bits of precision encoded with M <= N bits and no sign
> information.  That obviously leaves operations on numbers of
> that representation with differing N undefined.  You define it
> by having coded the operations which as far as I can see simply
> assume N is equal for any two operands and the effective sign for
> extending the M-bits encoding to the common N-bits precision is
> "available".  A thorough specification of both the encoding scheme
> and the operation semantics is missing.  I can side-step both of
> these issues nicely by simply using a infinite precision signed
> representation and requiring the client to explicitely truncate /
> extend to a specific precision when required.  I also leave open
> the possibility to have the _encoding_ be always the same as an
> infinite precision signed representation but to always require
> an explicitely specified target precision for each operation
> (which rules out the use of operator overloading).

For efficiency, the machine representation of an infinite precision
number should allow for a compact one-word representation.

  class infinite
  {
    int length;
    union representation
    {
         int inside_word;
         int *outside_words;
    } field;
  public:
    int mod_one_word()
    {
      if (length == 1)
        return field.inside_word;
      else
        return field.outside_word[0];
    }
  };

Also for efficiency, you want to know the modulus at the time you
do the last normal operation on it, not as a subsequent operation.

> Citing your example:
>
>   8 * 10 / 4
>
> and transforming it slightly into a commonly used pattern:
>
>   (byte-size * 8 + bit-size) / 8
>
> then I argue that what people want here is this carried out in
> _infinite_ precision!

But what people want isn't really relevant, what is relevant is
what the language and/or compatiblity requires.  Ideally, gcc
should accurately represent languages with both finite size and
infinite size.

> Even if byte-size happens to come from
> a sizetype TREE_INT_CST with 64bit precision.  So either
> choice - having a fixed-precision representation or an
> infinite-precision representation - can and will lead to errors
> done by the programmer.  And as you can easily build a
> finite precision wrapper around an infinite precision implementation
> but not the other way around it's obvious to me what the
> implementation should provide.

IIUC, the issue here is not the logical chain of implementation, but
the interface that is most helpful to the programmers in getting to
performant, correct code.  I expect we need the infinite precision
forms, but also that having more concise coding for fixed-precision
would be helpful.

For mixed operations, all the languages that I know of promote
smaller operands to larger operands, so I think a reasonable
definition is possible here.

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 19:14                                                                                                           ` Robert Dewar
@ 2013-04-08 23:48                                                                                                             ` Lawrence Crowl
  2013-04-09  1:22                                                                                                               ` Robert Dewar
  0 siblings, 1 reply; 217+ messages in thread
From: Lawrence Crowl @ 2013-04-08 23:48 UTC (permalink / raw)
  To: Robert Dewar
  Cc: Kenneth Zadeck, Florian Weimer, Richard Biener, Mike Stump,
	gcc-patches, rdsandiford, Ian Lance Taylor

On 4/8/13, Robert Dewar <dewar@adacore.com> wrote:
> On 4/8/2013 10:26 AM, Kenneth Zadeck wrote:
> > On 04/08/2013 10:12 AM, Robert Dewar wrote:
> > > On 4/8/2013 9:58 AM, Kenneth Zadeck wrote:
> > > > yes but the relevant question for the not officially
> > > > static integer constants is "in what precision are those
> > > > operations to be performed in?  I assume that you choose
> > > > gcc types for these operations and you expect the math to
> > > > be done within that type, i.e. exactly the way you expect
> > > > the machine to perform.
> > >
> > > As I explained in an earlier message, *within* a single
> > > expression, we are free to use higher precision, and we provide
> > > modes that allow this up to and including the usea of infinite
> > > precision. That applies not just to constant expressions but
> > > to all expressions.
> >
> > My confusion is what you mean by "we"?  Do you mean "we" the
> > writer of the program, "we" the person invoking the compiler
> > by the use command line options or "we", your company's
> > implementation of ada?
>
> Sorry, bad usage, The gcc implementation of Ada allows the user
> to specify by pragmas how intermediate overflow is handled.

Correct me if I'm wrong, but the Ada standard doesn't require any
particular maximum evaluation precision, but only that you get an
exception if the values exceed the chosen maximum.

> > My interpretation of your first email was that it was possible
> > for the programmer to do something equivalent to adding
> > attributes surrounding a block in the program to control the
> > precision and overflow detection of the expressions in the block.
> > And if this is so, then by the time the expression is seen by
> > the middle end of gcc, those attributes will have been converted
> > into tree code will evaluate the code in a well defined way by
> > both the optimization passes and the target machine.
>
> Yes, that's a correct understanding

In essence, you have moved some of the optimization from the back
end to the front end.  Correct?

-- 
Lawrence Crowl

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 23:48                                                                                                             ` Lawrence Crowl
@ 2013-04-09  1:22                                                                                                               ` Robert Dewar
  2013-04-09  1:56                                                                                                                 ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Robert Dewar @ 2013-04-09  1:22 UTC (permalink / raw)
  To: Lawrence Crowl
  Cc: Kenneth Zadeck, Florian Weimer, Richard Biener, Mike Stump,
	gcc-patches, rdsandiford, Ian Lance Taylor

On 4/8/2013 5:12 PM, Lawrence Crowl wrote:

(BTW, you *really* don't need to quote entire messages, I find
it rather redundant for the entire thread to be in every message,
we all have thread following mail readers!)

> Correct me if I'm wrong, but the Ada standard doesn't require any
> particular maximum evaluation precision, but only that you get an
> exception if the values exceed the chosen maximum.

Right, that's at run-time, at compile-time for static expressions,
infinite precision is required.

But at run-time, all three of the modes we provide are
standard conforming.

> In essence, you have moved some of the optimization from the back
> end to the front end.  Correct?

Sorry, I don't quite understand that. If you are syaing that the
back end could handle this widening for intermediate values, sure
it could, this is the kind of thing that can be done at various
different places.
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-09  1:22                                                                                                               ` Robert Dewar
@ 2013-04-09  1:56                                                                                                                 ` Kenneth Zadeck
  2013-04-09  2:10                                                                                                                   ` Robert Dewar
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-09  1:56 UTC (permalink / raw)
  To: Robert Dewar
  Cc: Lawrence Crowl, Florian Weimer, Richard Biener, Mike Stump,
	gcc-patches, rdsandiford, Ian Lance Taylor

In some sense you have to think in terms of three worlds:
1) what you call "compile-time static expressions" is one world which in 
gcc is almost always done by the front ends.
2) the second world is what the optimizers can do.   This is not 
compile-time static expressions because that is what the front end has 
already done.
3) there is run time.

My view on this is that optimization is just doing what is normally done 
at run time but doing it early.   From that point of view, we are if not 
required, morally obligated to do thing in the same way that the 
hardware would have done them.    This is why i am so against richi on 
wanting to do infinite precision.    By the time the middle or the back 
end sees the representation, all of the things that are allowed to be 
done in infinite precision have already been done.   What we are left 
with is a (mostly) strongly typed language that pretty much says exactly 
what must be done. Anything that we do in the middle end or back ends in 
infinite precision will only surprise the programmer and make them want 
to use llvm.

Kenny

On 04/08/2013 05:36 PM, Robert Dewar wrote:
> On 4/8/2013 5:12 PM, Lawrence Crowl wrote:
>
> (BTW, you *really* don't need to quote entire messages, I find
> it rather redundant for the entire thread to be in every message,
> we all have thread following mail readers!)
>
>> Correct me if I'm wrong, but the Ada standard doesn't require any
>> particular maximum evaluation precision, but only that you get an
>> exception if the values exceed the chosen maximum.
>
> Right, that's at run-time, at compile-time for static expressions,
> infinite precision is required.
>
> But at run-time, all three of the modes we provide are
> standard conforming.
>
>> In essence, you have moved some of the optimization from the back
>> end to the front end.  Correct?
>
> Sorry, I don't quite understand that. If you are syaing that the
> back end could handle this widening for intermediate values, sure
> it could, this is the kind of thing that can be done at various
> different places.
>>
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-09  1:56                                                                                                                 ` Kenneth Zadeck
@ 2013-04-09  2:10                                                                                                                   ` Robert Dewar
  2013-04-09  7:06                                                                                                                     ` Mike Stump
  0 siblings, 1 reply; 217+ messages in thread
From: Robert Dewar @ 2013-04-09  2:10 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Lawrence Crowl, Florian Weimer, Richard Biener, Mike Stump,
	gcc-patches, rdsandiford, Ian Lance Taylor

On 4/8/2013 5:46 PM, Kenneth Zadeck wrote:
> In some sense you have to think in terms of three worlds:
> 1) what you call "compile-time static expressions" is one world which in
> gcc is almost always done by the front ends.
> 2) the second world is what the optimizers can do.   This is not
> compile-time static expressions because that is what the front end has
> already done.
> 3) there is run time.
>
> My view on this is that optimization is just doing what is normally done
> at run time but doing it early.   From that point of view, we are if not
> required, morally obligated to do thing in the same way that the
> hardware would have done them.    This is why i am so against richi on
> wanting to do infinite precision.    By the time the middle or the back
> end sees the representation, all of the things that are allowed to be
> done in infinite precision have already been done.   What we are left
> with is a (mostly) strongly typed language that pretty much says exactly
> what must be done. Anything that we do in the middle end or back ends in
> infinite precision will only surprise the programmer and make them want
> to use llvm.

That may be so in C, in Ada it would be perfectly reasonable to use
infinite precision for intermediate results in some cases, since the
language standard specifically encourages this approach.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-09  2:10                                                                                                                   ` Robert Dewar
@ 2013-04-09  7:06                                                                                                                     ` Mike Stump
  2013-04-09  8:20                                                                                                                       ` Robert Dewar
  0 siblings, 1 reply; 217+ messages in thread
From: Mike Stump @ 2013-04-09  7:06 UTC (permalink / raw)
  To: Robert Dewar
  Cc: Kenneth Zadeck, Lawrence Crowl, Florian Weimer, Richard Biener,
	Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

On Apr 8, 2013, at 2:48 PM, Robert Dewar <dewar@adacore.com> wrote:
> That may be so in C, in Ada it would be perfectly reasonable to use
> infinite precision for intermediate results in some cases, since the
> language standard specifically encourages this approach.

gcc lacks an infinite precision plus operator?!  :-)

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-09  7:06                                                                                                                     ` Mike Stump
@ 2013-04-09  8:20                                                                                                                       ` Robert Dewar
  2013-04-09  8:22                                                                                                                         ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Robert Dewar @ 2013-04-09  8:20 UTC (permalink / raw)
  To: Mike Stump
  Cc: Kenneth Zadeck, Lawrence Crowl, Florian Weimer, Richard Biener,
	gcc-patches, rdsandiford, Ian Lance Taylor

On 4/8/2013 6:34 PM, Mike Stump wrote:
> On Apr 8, 2013, at 2:48 PM, Robert Dewar <dewar@adacore.com> wrote:
>> That may be so in C, in Ada it would be perfectly reasonable to use
>> infinite precision for intermediate results in some cases, since the
>> language standard specifically encourages this approach.
>
> gcc lacks an infinite precision plus operator?!  :-)
>
Right, that's why we do everything in the front end in the
case of Ada. But it would be perfectly reasonable for the
back end to do this substitution.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-09  8:20                                                                                                                       ` Robert Dewar
@ 2013-04-09  8:22                                                                                                                         ` Kenneth Zadeck
  2013-04-09  8:24                                                                                                                           ` Robert Dewar
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-09  8:22 UTC (permalink / raw)
  To: Robert Dewar
  Cc: Mike Stump, Lawrence Crowl, Florian Weimer, Richard Biener,
	gcc-patches, rdsandiford, Ian Lance Taylor


On 04/08/2013 06:45 PM, Robert Dewar wrote:
> On 4/8/2013 6:34 PM, Mike Stump wrote:
>> On Apr 8, 2013, at 2:48 PM, Robert Dewar <dewar@adacore.com> wrote:
>>> That may be so in C, in Ada it would be perfectly reasonable to use
>>> infinite precision for intermediate results in some cases, since the
>>> language standard specifically encourages this approach.
>>
>> gcc lacks an infinite precision plus operator?!  :-)
>>
> Right, that's why we do everything in the front end in the
> case of Ada. But it would be perfectly reasonable for the
> back end to do this substitution.
but there is no way in the current tree language to convey which ones 
you can and which ones you cannot.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-09  8:22                                                                                                                         ` Kenneth Zadeck
@ 2013-04-09  8:24                                                                                                                           ` Robert Dewar
  2013-04-09 12:42                                                                                                                             ` Florian Weimer
  0 siblings, 1 reply; 217+ messages in thread
From: Robert Dewar @ 2013-04-09  8:24 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, Lawrence Crowl, Florian Weimer, Richard Biener,
	gcc-patches, rdsandiford, Ian Lance Taylor

On 4/8/2013 7:46 PM, Kenneth Zadeck wrote:
>
> On 04/08/2013 06:45 PM, Robert Dewar wrote:
>> On 4/8/2013 6:34 PM, Mike Stump wrote:
>>> On Apr 8, 2013, at 2:48 PM, Robert Dewar <dewar@adacore.com> wrote:
>>>> That may be so in C, in Ada it would be perfectly reasonable to use
>>>> infinite precision for intermediate results in some cases, since the
>>>> language standard specifically encourages this approach.
>>>
>>> gcc lacks an infinite precision plus operator?!  :-)
>>>
>> Right, that's why we do everything in the front end in the
>> case of Ada. But it would be perfectly reasonable for the
>> back end to do this substitution.
> but there is no way in the current tree language to convey which ones
> you can and which ones you cannot.

Well the back end has all the information to figure this out I think!
But anyway, for Ada, the current situation is just fine, and has
the advantage that the -gnatG expanded code listing clearly shows in
Ada source form, what is going on.
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-08 22:34                                                                                               ` Lawrence Crowl
@ 2013-04-09  9:47                                                                                                 ` Richard Biener
       [not found]                                                                                                   ` <CAGqM8fZ7NxiMnC6PTA8v6w_E6ZJ5HbjhJXzh-HAOJqaSx+7rnw@mail.gmail.com>
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-09  9:47 UTC (permalink / raw)
  To: Lawrence Crowl
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, rdsandiford, Ian Lance Taylor

On Mon, Apr 8, 2013 at 10:39 PM, Lawrence Crowl <crowl@google.com> wrote:
> On 4/8/13, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> The other problem, which i invite you to use the full power of
>> your c++ sorcery on, is the one where defining an operator so
>> that wide-int + unsigned hwi is either rejected or properly
>> zero extended.  If you can do this, I will go along with
>> your suggestion that the internal rep should be sign extended.
>> Saying that constants are always sign extended seems ok, but there
>> are a huge number of places where we convert unsigned hwis as
>> the second operand and i do not want that to be a trap.  I went
>> thru a round of this, where i did not post the patch because i
>> could not make this work.  And the number of places where you
>> want to use an hwi as the second operand dwarfs the number of
>> places where you want to use a small integer constant.
>
> You can use overloading, as in the following, which actually ignores
> handling the sign in the representation.
>
> class number {
>         unsigned int rep1;
>         int representation;
> public:
>         number(int arg) : representation(arg) {}
>         number(unsigned int arg) : representation(arg) {}
>         friend number operator+(number, int);
>         friend number operator+(number, unsigned int);
>         friend number operator+(int, number);
>         friend number operator+(unsigned int, number);
> };
>
> number operator+(number n, int si) {
>     return n.representation + si;
> }
>
> number operator+(number n, unsigned int ui) {
>     return n.representation + ui;
> }
>
> number operator+(int si, number n) {
>     return n.representation + si;
> }
>
> number operator+(unsigned int ui, number n) {
>     return n.representation + ui;
> }

That does not work for types larger than int/unsigned int as HOST_WIDE_INT
usually is (it's long / unsigned long).  When you pass an int or unsigned int
to

number operator+(unsigned long ui, number n);
number operator+(long ui, number n)

you get an ambiguity.  You can "fix" that by relying on template argument
deduction and specialization instead of on overloading and integer conversion
rules.

> If the argument type is of a template type parameter, then
> you can test the template type via
>
>     if (std::is_signed<T>::value)
>       .... // sign extend
>     else
>       .... // zero extend
>
> See http://www.cplusplus.com/reference/type_traits/is_signed/.

Yes, if we want to use the standard library.  For what integer types
is std::is_signed required to be implemented in C++98 (long long?)?
Consider non-GCC host compilers.

Richard.

> If you want to handle non-builtin types that are asigne dor unsigned,
> then you need to add a specialization for is_signed.
>
> --
> Lawrence Crowl

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-09  8:24                                                                                                                           ` Robert Dewar
@ 2013-04-09 12:42                                                                                                                             ` Florian Weimer
  2013-04-09 15:06                                                                                                                               ` Robert Dewar
  0 siblings, 1 reply; 217+ messages in thread
From: Florian Weimer @ 2013-04-09 12:42 UTC (permalink / raw)
  To: Robert Dewar
  Cc: Kenneth Zadeck, Mike Stump, Lawrence Crowl, Richard Biener,
	gcc-patches, rdsandiford, Ian Lance Taylor

On 04/09/2013 01:47 AM, Robert Dewar wrote:
> Well the back end has all the information to figure this out I think!
> But anyway, for Ada, the current situation is just fine, and has
> the advantage that the -gnatG expanded code listing clearly shows in
> Ada source form, what is going on.

Isn't this a bit optimistic, considering that run-time overflow checking 
currently does not use existing hardware support?

-- 
Florian Weimer / Red Hat Product Security Team

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-09 12:42                                                                                                                             ` Florian Weimer
@ 2013-04-09 15:06                                                                                                                               ` Robert Dewar
  2013-04-09 16:16                                                                                                                                 ` Florian Weimer
  0 siblings, 1 reply; 217+ messages in thread
From: Robert Dewar @ 2013-04-09 15:06 UTC (permalink / raw)
  To: Florian Weimer
  Cc: Kenneth Zadeck, Mike Stump, Lawrence Crowl, Richard Biener,
	gcc-patches, rdsandiford, Ian Lance Taylor

On 4/9/2013 5:39 AM, Florian Weimer wrote:
> On 04/09/2013 01:47 AM, Robert Dewar wrote:
>> Well the back end has all the information to figure this out I think!
>> But anyway, for Ada, the current situation is just fine, and has
>> the advantage that the -gnatG expanded code listing clearly shows in
>> Ada source form, what is going on.
>
> Isn't this a bit optimistic, considering that run-time overflow checking
> currently does not use existing hardware support?

Not clear what you mean here, we don't rely on the back end for run-time
overflow checking. What is over-optimistic here?

BTW, existing hardware support can be a dubious thing, you have
to be careful to evaluate costs, for instance you don't want to
use INTO on modern x86 targets!
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-09 15:06                                                                                                                               ` Robert Dewar
@ 2013-04-09 16:16                                                                                                                                 ` Florian Weimer
  0 siblings, 0 replies; 217+ messages in thread
From: Florian Weimer @ 2013-04-09 16:16 UTC (permalink / raw)
  To: Robert Dewar
  Cc: Kenneth Zadeck, Mike Stump, Lawrence Crowl, Richard Biener,
	gcc-patches, rdsandiford, Ian Lance Taylor

On 04/09/2013 02:41 PM, Robert Dewar wrote:
> On 4/9/2013 5:39 AM, Florian Weimer wrote:
>> On 04/09/2013 01:47 AM, Robert Dewar wrote:
>>> Well the back end has all the information to figure this out I think!
>>> But anyway, for Ada, the current situation is just fine, and has
>>> the advantage that the -gnatG expanded code listing clearly shows in
>>> Ada source form, what is going on.
>>
>> Isn't this a bit optimistic, considering that run-time overflow checking
>> currently does not use existing hardware support?
>
> Not clear what you mean here, we don't rely on the back end for run-time
> overflow checking. What is over-optimistic here?
>
> BTW, existing hardware support can be a dubious thing, you have
> to be careful to evaluate costs, for instance you don't want to
> use INTO on modern x86 targets!

It's not aobut INTO, just access to the overflow flag.

A simple function which adds its two Integer arguments compiles to this 
machine code (with -gnato -O2):

	.cfi_startproc
	movslq	%esi, %rax
	movslq	%edi, %rdx
	addq	%rax, %rdx
	movl	$2147483648, %eax
	addq	%rax, %rdx
	movl	$4294967295, %eax
	cmpq	%rax, %rdx
	ja	.L5
	leal	(%rsi,%rdi), %eax
	ret
.L5:
	pushq	%rax
	.cfi_def_cfa_offset 16
	movl	$3, %esi
	movl	$.LC0, %edi
	xorl	%eax, %eax
	call	__gnat_rcheck_10
	.cfi_endproc

While it could be like this:

	.cfi_startproc
	movl    %edi, %eax
	addl    %esi, %eax
	jo	.L5
	ret
.L5:
	pushq	%rax
	.cfi_def_cfa_offset 16
	movl	$3, %esi
	movl	$.LC0, %edi
	xorl	%eax, %eax
	call	__gnat_rcheck_10
	.cfi_endproc

Admittedly, I haven't benchmarked it, but at least from the code size 
aspect, it's a significant improvement.

-- 
Florian Weimer / Red Hat Product Security Team

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
       [not found]                                                                                                   ` <CAGqM8fZ7NxiMnC6PTA8v6w_E6ZJ5HbjhJXzh-HAOJqaSx+7rnw@mail.gmail.com>
@ 2013-04-10  9:44                                                                                                     ` Richard Biener
  2013-04-10 17:43                                                                                                       ` Mike Stump
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-10  9:44 UTC (permalink / raw)
  To: Lawrence Crowl
  Cc: Ian Lance Taylor, Richard Sandiford, Mike Stump, Kenneth Zadeck,
	gcc-patches

On Tue, Apr 9, 2013 at 5:36 PM, Lawrence Crowl <crowl@google.com> wrote:
>
> On Apr 9, 2013 2:02 AM, "Richard Biener" <richard.guenther@gmail.com> wrote:
>>
>> On Mon, Apr 8, 2013 at 10:39 PM, Lawrence Crowl <crowl@google.com> wrote:
>> > On 4/8/13, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> >> The other problem, which i invite you to use the full power of
>> >> your c++ sorcery on, is the one where defining an operator so
>> >> that wide-int + unsigned hwi is either rejected or properly
>> >> zero extended.  If you can do this, I will go along with
>> >> your suggestion that the internal rep should be sign extended.
>> >> Saying that constants are always sign extended seems ok, but there
>> >> are a huge number of places where we convert unsigned hwis as
>> >> the second operand and i do not want that to be a trap.  I went
>> >> thru a round of this, where i did not post the patch because i
>> >> could not make this work.  And the number of places where you
>> >> want to use an hwi as the second operand dwarfs the number of
>> >> places where you want to use a small integer constant.
>> >
>> > You can use overloading, as in the following, which actually ignores
>> > handling the sign in the representation.
>> >
>> > class number {
>> >         unsigned int rep1;
>> >         int representation;
>> > public:
>> >         number(int arg) : representation(arg) {}
>> >         number(unsigned int arg) : representation(arg) {}
>> >         friend number operator+(number, int);
>> >         friend number operator+(number, unsigned int);
>> >         friend number operator+(int, number);
>> >         friend number operator+(unsigned int, number);
>> > };
>> >
>> > number operator+(number n, int si) {
>> >     return n.representation + si;
>> > }
>> >
>> > number operator+(number n, unsigned int ui) {
>> >     return n.representation + ui;
>> > }
>> >
>> > number operator+(int si, number n) {
>> >     return n.representation + si;
>> > }
>> >
>> > number operator+(unsigned int ui, number n) {
>> >     return n.representation + ui;
>> > }
>>
>> That does not work for types larger than int/unsigned int as HOST_WIDE_INT
>> usually is (it's long / unsigned long).  When you pass an int or unsigned
>> int
>> to
>>
>> number operator+(unsigned long ui, number n);
>> number operator+(long ui, number n)
>>
>> you get an ambiguity.  You can "fix" that by relying on template argument
>> deduction and specialization instead of on overloading and integer
>> conversion
>> rules.
>
> Ah, I hadn't quite gotten the point. This problem is being fixed in the
> standard, but that won't help GCC anytime soon.
>
>>
>> > If the argument type is of a template type parameter, then
>> > you can test the template type via
>> >
>> >     if (std::is_signed<T>::value)
>> >       .... // sign extend
>> >     else
>> >       .... // zero extend
>> >
>> > See http://www.cplusplus.com/reference/type_traits/is_signed/.
>>
>> Yes, if we want to use the standard library.  For what integer types
>> is std::is_signed required to be implemented in C++98 (long long?)?
>
> It is in C++03/TR1, which is our base requirement. Otherwise, we can test
> ~(T)0<(T)0.

Yeah, I think we want to test ~(T)0<(T)0 here.  Relying on C++03/TR1 is
too obscure if there is an easy workaround.

Richard.

>> Consider non-GCC host compilers.
>>
>> Richard.
>>
>> > If you want to handle non-builtin types that are asigne dor unsigned,
>> > then you need to add a specialization for is_signed.
>> >
>> > --
>> > Lawrence Crowl

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-10  9:44                                                                                                     ` Richard Biener
@ 2013-04-10 17:43                                                                                                       ` Mike Stump
  2013-04-10 17:53                                                                                                         ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Mike Stump @ 2013-04-10 17:43 UTC (permalink / raw)
  To: Richard Biener
  Cc: Lawrence Crowl, Ian Lance Taylor, Richard Sandiford, Mike Stump,
	Kenneth Zadeck, gcc-patches

On Apr 10, 2013, at 12:38 AM, Richard Biener <richard.guenther@gmail.com> wrote:
> Yeah, I think we want to test ~(T)0<(T)0 here.

Thanks Lawrence, in the next version of the patch, you will discover this at the bottom if you look hard.  :-)

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: Comments on the suggestion to use infinite precision math for wide int.
  2013-04-10 17:43                                                                                                       ` Mike Stump
@ 2013-04-10 17:53                                                                                                         ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-10 17:53 UTC (permalink / raw)
  To: Mike Stump
  Cc: Richard Biener, Lawrence Crowl, Ian Lance Taylor,
	Richard Sandiford, gcc-patches

On 04/10/2013 12:02 PM, Mike Stump wrote:
> On Apr 10, 2013, at 12:38 AM, Richard Biener <richard.guenther@gmail.com> wrote:
>> Yeah, I think we want to test ~(T)0<(T)0 here.
> Thanks Lawrence, in the next version of the patch, you will discover this at the bottom if you look hard.  :-)
actually closer to the middle.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-08 13:06                                                                               ` Richard Biener
@ 2013-04-17  0:49                                                                                 ` Kenneth Zadeck
  2013-04-17  3:41                                                                                   ` patch to fix constant math -5th patch, rtl Kenneth Zadeck
                                                                                                     ` (3 more replies)
  0 siblings, 4 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-17  0:49 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 2671 bytes --]

Richard,

I made major changes to wide-int along the lines you suggested. Each of 
the binary operations is now a template.
There are 5 possible implementations of those operations, one for each 
of HWI, unsigned HWI, wide-int, rtl, and tree.   Note that this is not 
exactly as you suggested, but it is along the same lines.

The HWI template sign extends the value to the precision of the first 
operand, the unsigned HWI is the same except that it is an unsigned 
extension.   The wide-int version is used as before, but is in truth 
rarely used.  The rtl and tree "logically" convert the value to a 
wide-int but in practice do something more efficient than converting to 
the wide-int.   What they do is look inside the rtl or the tree and pass 
a pointer to the data and a length to the binary operation.  This is 
perfectly safe in the position of a second operand to the binary 
operation because the lifetime is guaranteed to be very short.  The 
wide-int implementation was also modified to do the same pointer trick 
allowing all 5 templates to share the same use of the data.

Note that currently the tree code is more crufty than one would like.   
This will clean up nicely when the tree-cst is changed to represent the 
value with an array and a length field.

So now, at least for the second operand of binary operations, the 
storage is never copied.    I do not believe that there is a good 
similar trick for the first operand.  i did not consider something like 
wide_int::add (a, b) to be a viable option; it seems to mis the point of 
using an object oriented language.   So I think that you really have to 
copy the data into an instance of a wide int.

However, while all of this avoids ever having to pass a precision into 
the second operand, this patch does preserve the finite math 
implementation of wide-int.    Finite math is really what people expect 
an optimizer to do, because it seamlessly matches what the machine is 
going to do.

I hope at this point, i can get a comprehensive review on these patches. 
   I believe that I have done what is required.

There are two other patches that will be submitted in the next few 
minutes.   The first one is an updated version of the rtl level patch.   
The only changes from what you have seen before are that the binary 
operations now use the templated binary operations.  The second one is 
the first of the tree level patches.   It converts builtins.c to use 
both use wide-int and it removes all assumptions that tree-csts are 
built with two HWIs.

Once builtins.c is accepted, i will convert the rest of the middle end 
patches.   They will all be converted in a similar way.

Kenny

[-- Attachment #2: p4-6.diff --]
[-- Type: text/x-patch, Size: 152258 bytes --]

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 109f865..514fabc 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -857,7 +857,7 @@ RTL_BASE_H = coretypes.h rtl.h rtl.def $(MACHMODE_H) reg-notes.def \
   insn-notes.def $(INPUT_H) $(REAL_H) statistics.h $(VEC_H) \
   $(FIXED_VALUE_H) alias.h $(HASHTAB_H)
 FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h
-RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h
+RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h wide-int.h
 RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H)
 READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
 PARAMS_H = params.h params.def
@@ -945,7 +945,7 @@ TREE_PRETTY_PRINT_H = tree-pretty-print.h $(PRETTY_PRINT_H)
 GIMPLE_PRETTY_PRINT_H = gimple-pretty-print.h $(TREE_PRETTY_PRINT_H)
 DIAGNOSTIC_CORE_H = diagnostic-core.h $(INPUT_H) bversion.h diagnostic.def
 DIAGNOSTIC_H = diagnostic.h $(DIAGNOSTIC_CORE_H) $(PRETTY_PRINT_H)
-DWARF2OUT_H = dwarf2out.h $(DWARF2_H)
+DWARF2OUT_H = dwarf2out.h $(DWARF2_H) wide-int.h
 C_PRETTY_PRINT_H = c-family/c-pretty-print.h $(PRETTY_PRINT_H) \
 	$(C_COMMON_H) $(TREE_H)
 SCEV_H = tree-scalar-evolution.h $(GGC_H) tree-chrec.h $(PARAMS_H)
@@ -1458,6 +1458,7 @@ OBJS = \
 	varpool.o \
 	vmsdbgout.o \
 	web.o \
+	wide-int.o \
 	xcoffout.o \
 	$(out_object_file) \
 	$(EXTRA_OBJS) \
@@ -2687,6 +2688,7 @@ targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
    tree-ssa-alias.h $(TREE_FLOW_H)
 common/common-targhooks.o : common/common-targhooks.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(INPUT_H) $(TM_H) $(COMMON_TARGET_H) common/common-targhooks.h
+wide-int.o: wide-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
 
 bversion.h: s-bversion; @true
 s-bversion: BASE-VER
@@ -2853,10 +2855,10 @@ emit-rtl.o : emit-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(HASHTAB_H) $(TM_P_H) debug.h langhooks.h $(TREE_PASS_H) gt-emit-rtl.h \
    $(DF_H) $(PARAMS_H) $(TARGET_H)
 real.o : real.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
-   $(DIAGNOSTIC_CORE_H) $(TM_P_H) $(REAL_H) dfp.h realmpfr.h
+   $(DIAGNOSTIC_CORE_H) $(TM_P_H) $(REAL_H) dfp.h realmpfr.h wide-int.h
 realmpfr.o : realmpfr.c realmpfr.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(REAL_H) $(TREE_H)
 dfp.o : dfp.c dfp.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H)	$(TREE_H) \
-   $(TM_P_H) $(REAL_H) $(DECNUM_H)
+   $(TM_P_H) $(REAL_H) $(DECNUM_H) wide-int.h
 fixed-value.o: fixed-value.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) $(REAL_H) $(DIAGNOSTIC_CORE_H)
 jump.o : jump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
@@ -3941,15 +3943,16 @@ CFLAGS-gengtype-parse.o += -DGENERATOR_FILE
 build/gengtype-parse.o: $(BCONFIG_H)
 
 gengtype-state.o build/gengtype-state.o: gengtype-state.c $(SYSTEM_H) \
-  gengtype.h errors.h double-int.h version.h $(HASHTAB_H) $(OBSTACK_H) \
-  $(XREGEX_H)
+  gengtype.h errors.h double-int.h version.h $(HASHTAB_H)    \
+  $(OBSTACK_H) $(XREGEX_H)
 gengtype-state.o: $(CONFIG_H)
 CFLAGS-gengtype-state.o += -DGENERATOR_FILE
 build/gengtype-state.o: $(BCONFIG_H)
-
+wide-int.h: $(GTM_H) $(TREE_H) hwint.h $(OPTIONS_H) $(TM_H)             \
+  $(MACHMODE_H) double-int.h dumpfile.h $(REAL_H)
 gengtype.o build/gengtype.o : gengtype.c $(SYSTEM_H) gengtype.h 	\
-  rtl.def insn-notes.def errors.h double-int.h version.h $(HASHTAB_H) \
-  $(OBSTACK_H) $(XREGEX_H)
+  rtl.def insn-notes.def errors.h double-int.h wide-int.h version.h     \
+  $(HASHTAB_H) $(OBSTACK_H) $(XREGEX_H)
 gengtype.o: $(CONFIG_H)
 CFLAGS-gengtype.o += -DGENERATOR_FILE
 build/gengtype.o: $(BCONFIG_H)
diff --git a/gcc/wide-int.c b/gcc/wide-int.c
new file mode 100644
index 0000000..80f1981
--- /dev/null
+++ b/gcc/wide-int.c
@@ -0,0 +1,3164 @@
+/* Operations with very long integers.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hwint.h"
+#include "wide-int.h"
+#include "rtl.h"
+#include "tree.h"
+#include "dumpfile.h"
+
+/* This is the maximal size of the buffer needed for dump.  */
+const int MAX_SIZE = 4 * (MAX_BITSIZE_MODE_ANY_INT / 4
+		     + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
+
+/*
+ * Internal utilities.
+ */
+
+/* Quantities to deal with values that hold half of a wide int.  Used
+   in multiply and divide.  */
+#define HALF_INT_MASK (((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1)
+
+#define BLOCK_OF(TARGET) ((TARGET) / HOST_BITS_PER_WIDE_INT)
+#define BLOCKS_NEEDED(PREC) \
+  (((PREC) + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+#define SIGN_MASK(X) (((HOST_WIDE_INT)X) >> (HOST_BITS_PER_WIDE_INT - 1))
+/*
+ * Conversion routines in and out of wide-int.
+ */
+
+/* Convert OP0 into a wide int of PRECISION.  If the precision is less
+   than HOST_BITS_PER_WIDE_INT, zero extend the value of the word.
+   The overflow bit are set if the number was too large to fit in the
+   mode.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0,
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT t = sext_hwi (op0, precision);
+      if (t != op0 && overflow)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+  result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wh ("wide_int::from_shwi %s " HOST_WIDE_INT_PRINT_HEX ")\n",
+	      result, op0);
+#endif
+
+  return result;
+}
+
+/* Convert OP0 into a wide int of PRECISION.  If the precision is less
+   than HOST_BITS_PER_WIDE_INT, zero extend the value of the word.
+   The overflow bit are set if the number was too large to fit in the
+   mode.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, 
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT t = zext_hwi (op0, precision);
+      if (t != op0 && overflow)
+	*overflow = true;
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && precision > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wh ("wide_int::from_uhwi %s " HOST_WIDE_INT_PRINT_HEX ")\n",
+	      result, op0);
+#endif
+
+  return result;
+}
+
+/* Create a wide_int from an array of host_wide_ints in OP1 of LEN.
+   The result has PRECISION.  */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT *op1, unsigned int len, 
+		      unsigned int precision, bool need_canon)
+{
+  unsigned int i;
+  wide_int result;
+  
+  result.len = len;
+  result.precision = precision;
+
+  for (i=0; i < len; i++)
+    result.val[i] = op1[i];
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Convert a double int into a wide int with precision PREC.  */
+
+wide_int
+wide_int::from_double_int (double_int di, unsigned int prec)
+{
+  HOST_WIDE_INT op = di.low;
+  wide_int result;
+
+  result.precision = prec;
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result.val[0] = sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    result.val[1] = sext_hwi (di.high, prec);
+	  else
+	    result.val[1] = di.high;
+	}
+    }
+
+  if (result.len == 2)
+    result.canonize ();
+
+  return result;
+}
+
+/* Convert a integer cst into a wide int.  */
+
+wide_int
+wide_int::from_tree (const_tree tcst)
+{
+  wide_int result;
+  tree type = TREE_TYPE (tcst);
+  unsigned int prec = TYPE_PRECISION (type);
+
+  result.precision = prec;
+
+  /* This will simplify out to just an array copy and a len copy.  */
+  result.val[0] = TREE_INT_CST_LOW (tcst);
+  result.val[1] = TREE_INT_CST_HIGH (tcst);
+  if (prec == HOST_BITS_PER_DOUBLE_INT 
+      && TYPE_UNSIGNED (type)
+      && TREE_INT_CST_HIGH (tcst) < 0)
+    {
+      result.val[2] = 0;
+      result.len = 3;
+    }
+  else if (prec > HOST_BITS_PER_WIDE_INT)
+    result.len = 2;
+  else if (prec == HOST_BITS_PER_WIDE_INT
+	   && TYPE_UNSIGNED (type)
+	   && (HOST_WIDE_INT)TREE_INT_CST_LOW (tcst) < 0)
+    result.len = 2;
+  else
+    result.len = 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    {
+      debug_whh ("wide_int:: %s = from_tree ("HOST_WIDE_INT_PRINT_HEX" "HOST_WIDE_INT_PRINT_HEX")\n",
+		 result, TREE_INT_CST_HIGH (tcst), TREE_INT_CST_LOW (tcst));
+    }
+#endif
+
+  return result;
+}
+
+/* Extract a constant integer from the X of type MODE.  The bits of
+   the integer are returned.  */
+
+wide_int
+wide_int::from_rtx (const_rtx x, enum machine_mode mode)
+{
+  wide_int result;
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  gcc_assert (mode != VOIDmode);
+
+  result.precision = prec;
+
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+      result.val[0] = INTVAL (x);
+      result.len = 1;
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	{
+	  debug_wh ("wide_int:: %s = from_rtx ("HOST_WIDE_INT_PRINT_HEX")\n",
+		    result, INTVAL (x));
+	}
+#endif
+      break;
+
+#if TARGET_SUPPORTS_WIDE_INT
+    case CONST_WIDE_INT:
+      {
+	int i;
+	result.len = CONST_WIDE_INT_NUNITS (x);
+	
+	for (i = 0; i < result.len; i++)
+	  result.val[i] = CONST_WIDE_INT_ELT (x, i);
+      }
+      break;
+#else
+    case CONST_DOUBLE:
+      result.len = 2;
+      result.val[0] = CONST_DOUBLE_LOW (x);
+      result.val[1] = CONST_DOUBLE_HIGH (x);
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	{
+	  debug_whh ("wide_int:: %s = from_rtx ("HOST_WIDE_INT_PRINT_HEX" "HOST_WIDE_INT_PRINT_HEX")\n",
+		     result, CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
+	}
+#endif
+
+      break;
+#endif
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return result;
+}
+
+/* Construct from a buffer of length LEN.  BUFFER will be read according
+   to byte endianess and word endianess.  Only the lower LEN bytes
+   of the result are set; the remaining high bytes are cleared.  */
+
+wide_int
+wide_int::from_buffer (const unsigned char *buffer, int len)
+{
+  wide_int result = wide_int::zero (len * BITS_PER_UNIT);
+  int words = len / UNITS_PER_WORD;
+
+  for (int byte = 0; byte < len; byte++)
+    {
+      int offset;
+      int index;
+      int bitpos = byte * BITS_PER_UNIT;
+      unsigned HOST_WIDE_INT value;
+
+      if (len > UNITS_PER_WORD)
+	{
+	  int word = byte / UNITS_PER_WORD;
+
+	  if (WORDS_BIG_ENDIAN)
+	    word = (words - 1) - word;
+
+	  offset = word * UNITS_PER_WORD;
+
+	  if (BYTES_BIG_ENDIAN)
+	    offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
+	  else
+	    offset += byte % UNITS_PER_WORD;
+	}
+      else
+	offset = BYTES_BIG_ENDIAN ? (len - 1) - byte : byte;
+
+      value = (unsigned HOST_WIDE_INT) buffer[offset];
+
+      index = bitpos / HOST_BITS_PER_WIDE_INT;
+      result.val[index] |= value << bitpos;
+    }
+
+  result.canonize ();
+  return result;
+}
+
+
+/*
+ * Largest and smallest values in a mode.
+ */
+
+/* Produce the largest SGNed number that is represented in PREC.  The
+   resulting number is placed in a wide int of size PRECISION.  */
+
+wide_int
+wide_int::max_value (unsigned int prec, unsigned int precision, 
+		     SignOp sgn)
+{
+  wide_int result;
+  
+  result.precision = precision;
+
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned max is just all ones, for which the compressed
+	 rep is just a single HWI.  */ 
+      result.len = 1;
+      result.val[0] = (HOST_WIDE_INT)-1;
+    }
+  else
+    {
+      /* The signed max is all ones except the top bit.  This must be
+	 explicitly represented.  */
+      int i;
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      int shift = (small_prec == 0) 
+	? HOST_BITS_PER_WIDE_INT - 1 : small_prec - 1;
+
+      result.len = BLOCKS_NEEDED (prec);
+      for (i = 0; i < result.len - 1; i++)
+	result.val[i] = (HOST_WIDE_INT)-1;
+
+      result.val[result.len - 1] = ((HOST_WIDE_INT)1 << shift) - 1;
+    }
+  
+  return result;
+}
+
+/* Produce the smallest SGNed number that is represented in PREC.  The
+   resulting number is placed in a wide int of size PRECISION.  */
+
+wide_int
+wide_int::min_value (unsigned int prec, unsigned int precision, 
+		     SignOp sgn)
+{
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned min is just all zeros, for which the compressed
+	 rep is just a single HWI.  */ 
+      wide_int result;
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = 0;
+      return result;
+    }
+  else
+    {
+      /* The signed min is all zeros except the top bit.  This must be
+	 explicitly represented.  */
+      return set_bit_in_zero (prec - 1, precision);
+    }
+}
+
+/*
+ * Public utilities.
+ */
+
+/* Check the upper HOST_WIDE_INTs of src to see if the length can be
+   shortened.  An upper HOST_WIDE_INT is unnecessary if it is all ones
+   or zeros and the top bit of the next lower word matches.
+
+   This function may change the representation of THIS, but does not
+   change the value that THIS represents.  It does not sign extend in
+   the case that the size of the mode is less than
+   HOST_BITS_PER_WIDE_INT.  */
+
+void
+wide_int::canonize ()
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT top;
+  int i;
+
+  if (len > blocks_needed)
+    len = blocks_needed;
+
+  /* Clean up the top bits for any mode that is not a multiple of a HWI.  */
+  if (len == blocks_needed && small_prec)
+    val[len - 1] = sext_hwi (val[len - 1], small_prec);
+
+  if (len == 1)
+    return;
+
+  top = val[len - 1];
+  if (top != 0 && top != (HOST_WIDE_INT)-1)
+    return;
+
+  /* At this point we know that the top is either 0 or -1.  Find the
+     first block that is not a copy of this.  */
+  for (i = len - 2; i >= 0; i--)
+    {
+      HOST_WIDE_INT x = val[i];
+      if (x != top)
+	{
+	  if (SIGN_MASK (x) == top)
+	    {
+	      len = i + 1;
+	      return;
+	    }
+
+	  /* We need an extra block because the top bit block i does
+	     not match the extension.  */
+	  len = i + 2;
+	  return;
+	}
+    }
+
+  /* The number is 0 or -1.  */
+  len = 1;
+}
+
+
+/* Make a copy of this.  */
+
+wide_int
+wide_int::copy () const
+{
+  wide_int result;
+  int i;
+
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+  return result;
+}
+
+
+/* Copy THIS replacing the precision with PREC.
+   It can do any of truncation, extension or copying.  */
+
+wide_int
+wide_int::force_to_size (unsigned int prec, SignOp sgn) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (prec);
+  int i;
+
+  result.precision = prec;
+  result.len = blocks_needed < len ? blocks_needed : len;
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+
+  if (prec >= precision) 
+    {
+      /* Expanding */
+      int small_precision = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+      /* The only case we care about is unsigned because the rep is
+	 inherantly signed.  */
+      if (sgn == UNSIGNED)
+	{
+	  /* The top block in the existing rep must be zero extended,
+	     but this is all the work we need to do.  */
+	  if (small_precision 
+	      && (len == BLOCKS_NEEDED (precision)
+		  || len == blocks_needed))
+	    result.val[len-1] = zext_hwi (result.val[len-1], small_precision);
+	  else if (len == BLOCKS_NEEDED (precision) 
+		   && len < blocks_needed
+		   && small_precision == 0
+		   && result.val[result.len - 1] < 0)
+		    /* We need to put the 0 block on top to keep the value
+		       from being sign extended.  */ 
+		    result.val[result.len++] = 0;
+	}
+    }
+  else
+    {
+      /* Truncating.  */
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      /* The only weird case we need to look at here is when we are
+         truncating within the top block.  We need to make sure that
+         everything in the block above the new precision is sign
+         extended.  Note that this is independent of the SGN.  This is
+         just to stay canonical.  */
+      if (small_prec && (blocks_needed == len))
+	result.val[blocks_needed-1]
+	  = sext_hwi (result.val[blocks_needed-1], small_prec);
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwvs ("wide_int:: %s = force_to_size (%s, prec = %d %s)\n", 
+		 result, *this, prec, sgn==UNSIGNED ? "U" : "S");
+#endif
+
+  return result;
+}
+
+/*
+ * public printing routines.
+ */
+
+/* Try to print the signed self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_DEC, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decs (buf);
+  fputs (buf, file);
+}
+
+/* Try to print the unsigned self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decu (buf);
+  fputs (buf, file);
+}
+
+void 
+wide_int::print_hex (char *buf) const
+{
+  int i = len;
+
+  if (zero_p ())
+    sprintf (buf, "0x");
+  else
+    {
+      if (neg_p ())
+	{
+	  int j;
+	  /* If the number is negative, we may need to pad value with
+	     0xFFF...  because the leading elements may be missing and
+	     we do not print a '-' with hex.  */
+	  for (j = BLOCKS_NEEDED (precision); j > i; j--)
+	    buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, (HOST_WIDE_INT) -1);
+	    
+	}
+      else
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_HEX, val [--i]);
+      while (-- i >= 0)
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, val [i]);
+    }
+}
+
+/* Print one big hex number to FILE.  Note that some assemblers may not
+   accept this for large modes.  */
+void 
+wide_int::print_hex (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_hex (buf);
+  fputs (buf, file);
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently singed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+bool
+wide_int::eq_p_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  HOST_WIDE_INT op0mask = sign_mask ();
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  while (l0 > l1)
+    if (val[l0--] != op1mask)
+      return false;
+
+  while (l1 > l0)
+    if (op1[l1--] != op0mask)
+      return false;
+
+  while (l0 >= 0)
+    if (val[l0--] != op1[l1--])
+      return false;
+
+  return true;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p_large (const HOST_WIDE_INT *op0, unsigned int op0len, 
+		       const HOST_WIDE_INT *op1, unsigned int op1len, 
+		       unsigned int precision)
+{
+  int l;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  unsigned int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT op0mask = SIGN_MASK (op0[op0len - 1]);
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == op0len ? op0[blocks_needed - 1] : op0mask;
+  s1 = blocks_needed == op1len ? op1[blocks_needed - 1] : op1mask;
+  if (s0 < s1)
+    return true;
+  if (s0 > s1)
+    return false;
+
+  l = (signed int)MAX (op0len, op1len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == (signed int)blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < (signed int)op0len ? op0[l] : op0mask;
+      u1 = l < (signed int)op1len ? op1[l] : op1mask;
+
+      if (u0 < u1)
+	return true;
+      if (u0 > u1)
+	return false;
+      l--;
+    }
+
+  return false;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+int
+wide_int::cmps_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  int l;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  unsigned int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT op0mask = sign_mask ();
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == (unsigned int)len ? val[blocks_needed - 1] : op0mask;
+  s1 = blocks_needed == op1len ? op1[blocks_needed - 1] : op1mask;
+  if (s0 < s1)
+    return -1;
+  if (s0 > s1)
+    return 1;
+
+  l = MAX (len, (signed int)op1len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == (signed int)blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < len ? val [l] : op0mask;
+      u1 = l < (signed int)op1len ? op1[l] : op1mask;
+
+      if (u0 < u1)
+	return -1;
+      if (u0 > u1)
+	return 1;
+      l--;
+    }
+
+  return 0;
+}
+
+/* Return true if OP0 < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p_large (const HOST_WIDE_INT *op0, unsigned int op0len, 
+		       const HOST_WIDE_INT *op1, unsigned int op1len)
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = op0len - 1;
+  int l1 = op1len - 1;
+  HOST_WIDE_INT op0mask = SIGN_MASK (op0[op0len - 1]);
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  while (l0 > l1)
+    {
+      x0 = op0[l0--];
+      x1 = op1mask;
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  while (l1 > l0)
+    {
+      x0 = op0mask;
+      x1 = op1[l1--];
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = op0[l0--];
+      x1 = op1[l1--];
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  return false;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+int
+wide_int::cmpu_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  HOST_WIDE_INT op0mask = sign_mask ();
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1mask;
+      if (x0 < x1)
+	return -1;
+      else if (x0 > x1)
+	return 1;
+    }
+
+  while (l1 > l0)
+    {
+      x0 = op0mask;
+      x1 = op1[l1--];
+      if (x0 < x1)
+	return -1;
+      if (x0 > x1)
+	return 1;
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1[l1--];
+      if (x0 < x1)
+	return -1;
+      if (x0 > x1)
+	return 1;
+    }
+
+  return 0;
+}
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p (unsigned int prec) const
+{
+  int i;
+  HOST_WIDE_INT x;
+  int small_prec;
+  bool result;
+
+  if (BLOCKS_NEEDED (prec) != len)
+    {
+      result = false;
+      goto ex;
+    }
+
+  for (i=0; i < len - 1; i++)
+    if (val[i] != 0)
+      {
+	result = false;
+	goto ex;
+      }
+
+  x = val[len - 1];
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec)
+    x = x << (HOST_BITS_PER_WIDE_INT - small_prec);
+
+  result = x == ((HOST_WIDE_INT)1) << (HOST_BITS_PER_WIDE_INT - 1);
+
+ ex:
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = only_sign_bit_p (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Returns true if THIS fits into range of TYPE.  Signedness of OP0 is
+   assumed to be the same as the signedness of TYPE.  */
+
+bool
+wide_int::fits_to_tree_p (const_tree type) const
+{
+  int type_prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return fits_u_p (type_prec);
+  else
+    return fits_s_p (type_prec);
+}
+
+/* Returns true of THIS fits in the unsigned range of precision.  */
+
+bool
+wide_int::fits_s_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == sext (prec);
+}
+
+
+/* Returns true if THIS fits into range of TYPE.  */
+
+bool
+wide_int::fits_u_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == zext (prec);
+}
+
+/*
+ * Extension.
+ */
+
+/* Sign extend THIS starting at OFFSET.  The precision of the result
+   are the same as THIS.  */
+
+wide_int
+wide_int::sext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = sext_hwi (val[0], offset);
+      else
+	/* If offset is greater or equal to precision there is nothing
+	   to do since the internal rep is already sign extended.  */
+	result.val[0] = val[0];
+
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, precision);
+      
+      /* Now we can do the real sign extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      if (off)
+	{
+	  int block = BLOCK_OF (offset);
+	  result.val[block] = sext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      /* We never need an extra element for sign extended values.  */
+    }    
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s sext %d)\n", result, *this, offset);
+#endif
+
+  return result;
+}
+
+/* Zero extend THIS starting at OFFSET.  The precision of the result
+   are the same as THIS.  */
+
+wide_int
+wide_int::zext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+  int block;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = zext_hwi (val[0], offset);
+      else if (offset == precision)
+	result.val[0] = val[0];
+	/* If offset was greater than the precision we need to zero
+	   extend from the old precision since the internal rep was
+	   equivalent to sign extended.  */
+      else
+	result.val[0] = zext_hwi (val[0], precision);
+	
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, precision);
+
+      /* Now we can do the real zero extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      block = BLOCK_OF (offset);
+      if (off)
+	{
+	  result.val[block] = zext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      else
+	/* See if we need an extra zero element to satisfy the
+	   compression rule.  */
+	if (val[block - 1] < 0 && offset < precision)
+	  {
+	    result.val[block] = 0;
+	    result.len += 1;
+	  }
+    }
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s zext %d)\n", result, *this, offset);
+#endif
+  return result;
+}
+
+/*
+ * Masking, inserting, shifting, rotating.
+ */
+
+/* Return a value with a one bit inserted in THIS at BITPOS.  */
+
+wide_int
+wide_int::set_bit (unsigned int bitpos) const
+{
+  wide_int result;
+  int i, j;
+
+  if (bitpos >= precision)
+    result = copy ();
+  else
+    {
+      result = decompress (bitpos, precision);
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwv ("wide_int:: %s = (%s set_bit %d)\n", result, *this, bitpos);
+#endif
+  return result;
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with PRECISION.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, unsigned int prec)
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (bitpos + 1);
+  int i, j;
+
+  result.precision = prec;
+  if (bitpos >= prec)
+    {
+      result.len = 1;
+      result.val[0] = 0;
+    }
+  else
+    {
+      result.len = blocks_needed;
+      for (i = 0; i < blocks_needed; i++)
+	result.val[i] = 0;
+      
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wv ("wide_int:: %s = set_bit_in_zero (%d)\n", result, bitpos);
+#endif
+
+  return result;
+}
+
+/* Insert WIDTH bits from OP0 into THIS starting at START.  */
+
+wide_int
+wide_int::insert (const wide_int &op0, unsigned int start, 
+		  unsigned int width) const
+{
+  wide_int result;
+  wide_int mask;
+  wide_int tmp;
+
+  if (start + width >= precision) 
+    width = precision - start;
+
+  mask = shifted_mask (start, width, false, precision);
+  tmp = op0.lshift (start, 0, precision, NONE);
+  result = tmp & mask;
+
+  tmp = and_not (mask);
+  result = result | tmp;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwwvv ("wide_int:: %s = (%s insert %s start = %d width = %d)\n", 
+		 result, *this, op0, start, width);
+#endif
+
+  return result;
+}
+
+/* bswap THIS.  */
+
+wide_int
+wide_int::bswap () const
+{
+  wide_int result;
+  int i, s;
+  int end;
+  int len = BLOCKS_NEEDED (precision);
+
+  /* This is not a well defined operation if the precision is not a
+     multiple of 8.  */
+  gcc_assert ((precision & 0x7) == 0);
+
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < len; i++)
+    result.val[i] = 0;
+
+  /* Only swap the bytes that are not the padding.  */
+  if ((precision & (HOST_BITS_PER_WIDE_INT - 1))
+      && (this->len == len))
+    end = precision;
+  else
+    end = this->len * HOST_BITS_PER_WIDE_INT;
+
+  for (s = 0; s < end; s += 8)
+    {
+      unsigned int d = precision - s - 8;
+      unsigned HOST_WIDE_INT byte;
+
+      int block = s / HOST_BITS_PER_WIDE_INT;
+      int offset = s & (HOST_BITS_PER_WIDE_INT - 1);
+
+      byte = (val[block] >> offset) & 0xff;
+
+      block = d / HOST_BITS_PER_WIDE_INT;
+      offset = d & (HOST_BITS_PER_WIDE_INT - 1);
+
+      result.val[block] |= byte << offset;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = bswap (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with PREC. */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  int shift;
+
+  gcc_assert (width < 2 * MAX_BITSIZE_MODE_ANY_INT);
+  gcc_assert (prec <= 2 * MAX_BITSIZE_MODE_ANY_INT);
+
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (prec);
+      else
+	result = wide_int::zero (prec);
+    }
+  else
+    {
+      result.precision = prec;
+      
+      while (i < width / HOST_BITS_PER_WIDE_INT)
+	result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+      
+      shift = width & (HOST_BITS_PER_WIDE_INT - 1);
+      if (shift != 0)
+	{
+	  HOST_WIDE_INT last = (((HOST_WIDE_INT)1) << shift) - 1;
+	  result.val[i++] = negate ? ~last : last;
+	}
+      result.len = i;
+    }
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wvv ("wide_int:: %s = mask (%d, negate = %d)\n", result, width, negate);
+#endif
+  return result;
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  */
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  unsigned int shift;
+  unsigned int end = start + width;
+  HOST_WIDE_INT block;
+
+  if (start + width > prec)
+    width = prec - start;
+ 
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (prec);
+      else
+	result = wide_int::zero (prec);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wvvv 
+	  ("wide_int:: %s = shifted_mask (start = %d width = %d negate = %d)\n", 
+	   result, start, width, negate);
+#endif
+      return result;
+    }
+
+  result.precision = prec;
+
+  while (i < start / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? (HOST_WIDE_INT)-1 : 0;
+
+  shift = start & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift)
+    {
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      shift = (end) & (HOST_BITS_PER_WIDE_INT - 1);
+      if (shift)
+	{
+	  /* case 000111000 */
+	  block = (((HOST_WIDE_INT)1) << shift) - block - 1;
+	  result.val[i++] = negate ? ~block : block;
+	  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_wvvv 
+	      ("wide_int:: %s = shifted_mask (start = %d width = %d negate = %d)\n", 
+	       result, start, width, negate);
+#endif
+	  return result;
+	}
+      else
+	/* ...111000 */
+	result.val[i++] = negate ? block : ~block;
+    }
+
+  while (i < end / HOST_BITS_PER_WIDE_INT)
+    /* 1111111 */
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = end & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      /* 000011111 */
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~block : block;
+    }
+
+  result.len = i;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvvv 
+      ("wide_int:: %s = shifted_mask (start = %d width = %d negate = %d)\n", 
+       result, start, width, negate);
+#endif
+
+  return result;
+}
+
+
+/*
+ * logical operations.
+ */
+
+/* Return THIS & OP1.  */
+
+wide_int
+wide_int::and_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (SIGN_MASK (op1[op1len - 1]) == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & op1[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Return THIS & ~OP1.  */
+
+wide_int
+wide_int::and_not_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (SIGN_MASK (op1[op1len - 1]) != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & ~op1[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+wide_int
+wide_int::or_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (SIGN_MASK (op1[op1len - 1]) != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | op1[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+  return result;
+}
+
+/* Return THIS | ~OP1.  */
+
+wide_int
+wide_int::or_not_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (SIGN_MASK (op1[op1len - 1]) == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | ~op1[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Return the exclusive ior (xor) of THIS and OP1.  */
+
+wide_int
+wide_int::xor_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  while (l0 > l1)
+    {
+      result.val[l0] = val[l0] ^ SIGN_MASK (op1[op1len - 1]);
+      l0--;
+    }
+
+  while (l1 > l0)
+    {
+      result.val[l1] = sign_mask () ^ op1[l1];
+      l1--;
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] ^ op1[l0];
+      l0--;
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwa ("wide_int:: %s = (%s ^ %s)\n", result, *this, op1, op1len);
+#endif
+  return result;
+}
+
+/*
+ * math
+ */
+
+/* Absolute value of THIS.  */
+
+wide_int
+wide_int::abs () const
+{
+  if (sign_mask ())
+    return neg ();
+
+  wide_int result = copy ();
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = abs (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Add of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::add_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.precision = precision;
+  result.len = MAX (len, op1len);
+  mask0 = sign_mask ();
+  mask1 = SIGN_MASK (op1[op1len - 1]);
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1len ? (unsigned HOST_WIDE_INT)op1[i] : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 + mask1 + carry;
+      result.len++;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/* Add of OP0 and OP1 with overflow checking.  If the result overflows
+   within the precision, set OVERFLOW.  OVERFLOW is assumed to be
+   sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::add (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT old_carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int i, small_prec;
+
+  gcc_checking_assert (precision == op1.precision);
+
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < len; i++)
+    {
+      o0 = val[i];
+      o1 = op1.val[i];
+      x = o0 + o1 + carry;
+      result.val [i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+
+  /* Uncompress the rest.  */
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = val[i];
+      o1 = mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = mask0;
+      o1 = op1.val[i];
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 + mask1 + carry;
+      result.len++;
+      /* If we were short, we could not have overflowed.  */
+      goto ex;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (sgn == wide_int::SIGNED)
+	{
+	  if (((!(o0 ^ o1)) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
+	    *overflow = true;
+	}
+      else if (old_carry)
+	{
+	  if ((~o0) <= o1)
+	    *overflow = true;
+	}
+      else
+	{
+	  if ((~o0) < o1)
+	    *overflow = true;
+	}
+    }
+  else
+    {
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  If there are any non zero bits above the prec,
+	     we overflowed. */
+	  o0 = zext_hwi (o0, small_prec);
+	  o1 = zext_hwi (o1, small_prec);
+	  x = o0 + o1 + old_carry;
+	  if (x >> small_prec)
+	    *overflow = true;
+	}
+      else 
+	{
+	  /* Overflow in this case is easy since we can see bits beyond
+	     the precision.  If the value computed is not the sign
+	     extended value, then we have overflow.  */
+	  unsigned HOST_WIDE_INT y = sext_hwi (x, small_prec);
+	  if (x != y)
+	    *overflow = true;
+	}
+    }
+
+ ex:
+  result.canonize ();
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvww ("wide_int:: %s %d = (%s +O %s)\n", 
+	       result, *overflow, *this, op1);
+#endif
+
+  return result;
+}
+
+
+/* Count leading zeros of THIS but only looking at the bits in the
+   smallest HWI of size mode.  */
+
+wide_int
+wide_int::clz () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+    }
+  else
+    {
+      /* The high order block is special if it is the last block and the
+	 precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+	 have to clear out any ones above the precision before doing clz
+	 on this block.  */
+      if (BLOCKS_NEEDED (precision) == len && small_prec)
+	{
+	  v = zext_hwi (val[len - 1], small_prec);
+	  count = clz_hwi (v) - (HOST_BITS_PER_WIDE_INT - small_prec);
+	  start = len - 2;
+	  if (v != 0)
+	    {
+#ifdef DEBUG_WIDE_INT
+	      if (dump_file)
+		debug_vw ("wide_int:: %d = clz (%s)\n", count, *this);
+#endif
+	      return from_shwi (count, precision);
+	    }
+	}
+      else
+	{
+	  count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+	  start = len - 1;
+	}
+      
+      for (i = start; i >= 0; i--)
+	{
+	  v = elt (i);
+	  count += clz_hwi (v);
+	  if (v != 0)
+	    break;
+	}
+      
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = clz (%s)\n", count, *this);
+#endif
+  return from_shwi (count, precision);
+}
+
+/* Count the number of redundant leading bits of THIS.  Return result
+   as a HOST_WIDE_INT.  */
+
+wide_int
+wide_int::clrsb () const
+{
+  if (neg_p ())
+    return operator ~ ().clz () - 1;
+
+  return clz () - 1;
+}
+
+/* Count zeros of THIS.   */
+
+wide_int
+wide_int::ctz () const
+{
+  int i;
+  unsigned int count = 0;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int end;
+  bool more_to_do;
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+    }
+  else
+    {
+      /* The high order block is special if it is the last block and the
+	 precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+	 have to clear out any ones above the precision before doing clz
+	 on this block.  */
+      if (BLOCKS_NEEDED (precision) == len && small_prec)
+	{
+	  end = len - 1;
+	  more_to_do = true;
+	}
+      else
+	{
+	  end = len;
+	  more_to_do = false;
+	}
+      
+      for (i = 0; i < end; i++)
+	{
+	  v = val[i];
+	  count += ctz_hwi (v);
+	  if (v != 0)
+	    {
+#ifdef DEBUG_WIDE_INT
+	      if (dump_file)
+		debug_vw ("wide_int:: %d = ctz (%s)\n", count, *this);
+#endif
+	      return wide_int::from_shwi (count, precision);
+	    }
+	}
+      
+      if (more_to_do)
+	{
+	  v = zext_hwi (val[len - 1], small_prec);
+	  count = ctz_hwi (v);
+	  /* The top word was all zeros so we have to cut it back to prec,
+	     because we are counting some of the zeros above the
+	     interesting part.  */
+	  if (count > precision)
+	    count = precision;
+	}
+      else
+	/* Skip over the blocks that are not represented.  They must be
+	   all zeros at this point.  */
+	count = precision;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = ctz (%s)\n", count, *this);
+#endif
+  return wide_int::from_shwi (count, precision);
+}
+
+/* ffs of THIS.  */
+
+wide_int
+wide_int::ffs () const
+{
+  HOST_WIDE_INT count = ctz ().to_shwi ();
+  if (count == precision)
+    count = 0;
+  else
+    count += 1;
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = ffs (%s)\n", count, *this);
+#endif
+  return wide_int::from_shwi (count, precision);
+}
+
+/* Subroutines of the multiplication and division operations.  Unpack
+   the first IN_LEN HOST_WIDE_INTs in INPUT into 2 * IN_LEN
+   HOST_HALF_WIDE_INTs of RESULT.  The rest of RESULT is filled by
+   uncompressing the top bit of INPUT[IN_LEN - 1].  */
+
+static void
+wi_unpack (unsigned HOST_HALF_WIDE_INT *result, 
+	   const unsigned HOST_WIDE_INT *input,
+	   int in_len, int out_len)
+{
+  int i;
+  int j = 0;
+  HOST_WIDE_INT mask;
+
+  for (i = 0; i <in_len; i++)
+    {
+      result[j++] = input[i];
+      result[j++] = input[i] >> HOST_BITS_PER_HALF_WIDE_INT;
+    }
+  mask = SIGN_MASK (input[in_len - 1]);
+  mask &= HALF_INT_MASK;
+
+  /* Smear the sign bit.  */
+  while (j < out_len)
+    result[j++] = mask;
+}
+
+/* The inverse of wi_unpack.  IN_LEN is the the number of input
+   blocks.  The number of output blocks will be half this amount.  */
+
+static void
+wi_pack (unsigned HOST_WIDE_INT *result, 
+	 const unsigned HOST_HALF_WIDE_INT *input, 
+	 int in_len)
+{
+  int i = 0;
+  int j = 0;
+
+  while (i < in_len - 2)
+    {
+      result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+	| ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+      i += 2;
+    }
+
+  /* Handle the case where in_len is odd.   For this we zero extend.  */
+  if (i & 1)
+    result[j++] = (unsigned HOST_WIDE_INT)input[i];
+  else
+    result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+      | ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+}
+
+/* Return an integer that is the exact log2 of THIS.  */
+
+wide_int
+wide_int::exact_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  wide_int count;
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec)
+	v = zext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = wide_int::from_shwi (::exact_log2 (v), precision);
+    }
+  else
+    {
+      count = ctz ();
+      if (clz () + count + 1 == precision)
+	result = count;
+      else
+	result = wide_int::from_shwi (-1, precision);
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = exact_log2 (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Return an integer that is the floor log2 of THIS.  */
+
+wide_int
+wide_int::floor_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec)
+	v = zext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = wide_int::from_shwi (::floor_log2 (v), precision);
+    }
+  else
+    result = wide_int::from_shwi (precision, precision) - 1 - clz ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = floor_log2 (%s)\n", result, *this);
+#endif
+  return result;
+}
+
+
+/* Multiply Op1 by Op2.  If HIGH is set, only the upper half of the
+   result is returned.  If FULL is set, the entire result is returned
+   in a mode that is twice the width of the inputs.  However, that
+   mode needs to exist if the value is to be usable.  Clients that use
+   FULL need to check for this.
+
+   If HIGH or FULL are not setm throw away the upper half after the check
+   is made to see if it overflows.  Unfortunately there is no better
+   way to check for overflow than to do this.  OVERFLOW is assumed to
+   be sticky so it should be initialized.  SGN controls the signess
+   and is used to check overflow or if HIGH or FULL is set.  */
+
+wide_int
+wide_int::mul_internal (bool high, bool full, 
+			const wide_int *op1, 
+			const HOST_WIDE_INT *op2, unsigned int op2len,
+			wide_int::SignOp sgn,  bool *overflow, 
+			bool needs_overflow)
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1, k, t;
+  unsigned int i;
+  unsigned int j;
+  unsigned int prec = op1->get_precision ();
+  unsigned int blocks_needed = BLOCKS_NEEDED (prec);
+  unsigned int half_blocks_needed = blocks_needed * 2;
+  /* The sizes here are scaled to support a 2x largest mode by 2x
+     largest mode yielding a 4x largest mode result.  This is what is
+     needed by vpn.  */
+
+  unsigned HOST_HALF_WIDE_INT 
+    u[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT 
+    v[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  /* The '2' in 'R' is because we are internally doing a full
+     multiply.  */
+  unsigned HOST_HALF_WIDE_INT 
+    r[2 * 2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1;
+
+  /* If the top level routine did not really pass in an overflow, then
+     just make sure that we never attempt to set it.  */
+  if (overflow == 0)
+    needs_overflow = false;
+  result.precision = op1->precision;
+
+  if (high || full || needs_overflow)
+    {
+      /* If we need to check for overflow, we can only do half wide
+	 multiplies quickly because we need to look at the top bits to
+	 check for the overflow.  */
+      if (prec <= HOST_BITS_PER_HALF_WIDE_INT)
+	{
+	  HOST_WIDE_INT t, r;
+	  result.len = 1;
+	  o0 = op1->elt (0);
+	  o1 = op2[0];
+	  r = o0 * o1;
+	  /* Signed shift down will leave 0 or -1 if there was no
+	     overflow for signed or 0 for unsigned.  */
+	  t = SIGN_MASK (r);
+	  if (needs_overflow)
+	    {
+	      if (sgn == wide_int::SIGNED)
+		{
+		  if (t != (HOST_WIDE_INT)-1 && t != 0)
+		    *overflow = true;
+		}
+	      else
+		{
+		  if (t != 0)
+		    *overflow = true;
+		}
+	    }
+	  if (full)
+	    {
+	      result.val[0] = sext_hwi (r, prec * 2);
+	      result.precision = op1->precision * 2;
+	    }
+	  else if (high)
+	    result.val[0] = r >> prec;
+	  else
+	    result.val[0] = sext_hwi (r, prec);
+#ifdef DEBUG_WIDE_INT
+	  if (dump_file)
+	    debug_wvwa ("wide_int:: %s %d = (%s *O %s)\n", 
+			result, *overflow, *op1, op2, op2len);
+#endif
+	  return result;
+	}
+    }
+
+  wi_unpack (u, (const unsigned HOST_WIDE_INT*)op1->val, op1->len,
+	     half_blocks_needed);
+  wi_unpack (v, (const unsigned HOST_WIDE_INT*)op2, op2len,
+	     half_blocks_needed);
+
+  /* The 2 is for a full mult.  */
+  memset (r, 0, half_blocks_needed * 2 
+	  * HOST_BITS_PER_HALF_WIDE_INT / BITS_PER_UNIT);
+
+  for (j = 0; j < half_blocks_needed; j++)
+    {
+      k = 0;
+      for (i = 0; i < half_blocks_needed; i++)
+	{
+	  t = ((unsigned HOST_WIDE_INT)u[i] * (unsigned HOST_WIDE_INT)v[j]
+	       + r[i + j] + k);
+	  r[i + j] = t & HALF_INT_MASK;
+	  k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	}
+      r[j + half_blocks_needed] = k;
+    }
+
+  /* We did unsigned math above.  For signed we must adjust the
+     product (assuming we need to see that).  */
+  if (sgn == wide_int::SIGNED && (full || high || needs_overflow))
+    {
+      unsigned HOST_WIDE_INT b;
+      if ((*op1).neg_p ())
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)v[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+      if (op2[op2len-1] < 0)
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)u[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+    }
+
+  if (needs_overflow)
+    {
+      HOST_WIDE_INT top;
+
+      /* For unsigned, overflow is true if any of the top bits are set.
+	 For signed, overflow is true if any of the top bits are not equal
+	 to the sign bit.  */
+      if (sgn == wide_int::UNSIGNED)
+	top = 0;
+      else
+	{
+	  top = r[(half_blocks_needed) - 1];
+	  top = SIGN_MASK (top << (HOST_BITS_PER_WIDE_INT / 2));
+	  top &= mask;
+	}
+      
+      for (i = half_blocks_needed; i < half_blocks_needed * 2; i++)
+	if (((HOST_WIDE_INT)(r[i] & mask)) != top)
+	  *overflow = true; 
+    }
+
+  if (full)
+    {
+      /* compute [2prec] <- [prec] * [prec] */
+      wi_pack ((unsigned HOST_WIDE_INT*)result.val, r, 2 * half_blocks_needed);
+      result.len = blocks_needed * 2;
+      result.precision = op1->precision * 2;
+    }
+  else if (high)
+    {
+      /* compute [prec] <- ([prec] * [prec]) >> [prec] */
+      wi_pack ((unsigned HOST_WIDE_INT*)&result.val [blocks_needed >> 1],
+	       r, half_blocks_needed);
+      result.len = blocks_needed;
+    }
+  else
+    {
+      /* compute [prec] <- ([prec] * [prec]) && ((1 << [prec]) - 1) */
+      wi_pack ((unsigned HOST_WIDE_INT*)result.val, r, half_blocks_needed);
+      result.len = blocks_needed;
+    }
+      
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvwa ("wide_int:: %s %d = (%s *O %s)\n", 
+		result, *overflow, *op1, op2, op2len);
+#endif
+  return result;
+}
+
+/* Compute the parity of THIS.  */
+
+wide_int
+wide_int::parity () const
+{
+  wide_int count = popcount ();
+  return count & 1;
+}
+
+/* Compute the population count of THIS.  */
+
+wide_int
+wide_int::popcount () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = popcount_hwi (v);
+      start = len - 2;
+    }
+  else
+    {
+      if (sign_mask ())
+	count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      else
+	count = 0;
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = val[i];
+      count += popcount_hwi (v);
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vw ("wide_int:: %d = popcount (%s)\n", count, *this);
+#endif
+  return wide_int::from_shwi (count, precision);
+}
+
+/* Subtract of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::sub_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the borrow in of the first element at 1.  */
+  unsigned HOST_WIDE_INT borrow = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.precision = precision;
+  result.len = MAX (len, op1len);
+  mask0 = sign_mask ();
+  mask1 = SIGN_MASK (op1[op1len - 1]);
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1len ? (unsigned HOST_WIDE_INT)op1[i] : mask1;
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      borrow = o0 < o1;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 - mask1 - borrow;
+      result.len++;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/* Subtract of THIS and OP1 with overflow checking.  If the result
+   overflows within the precision, set OVERFLOW.  OVERFLOW is assumed
+   to be sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::sub (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT borrow = 0;
+  unsigned HOST_WIDE_INT old_borrow = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int i, small_prec;
+
+  gcc_checking_assert (precision == op1.precision);
+
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < len; i++)
+    {
+      o0 = val[i];
+      o1 = op1.val[i];
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  /* Uncompress the rest.  */
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = val[i];
+      o1 = mask1;
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  for (i = op1.len; i < len; i++)
+    {
+      o0 = mask0;
+      o1 = op1.val[i];
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 - mask1 - borrow;
+      result.len++;
+      /* If we were short, we could not have overflowed.  */
+    }
+  else
+    {
+      small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+      if (small_prec == 0)
+	{
+	  if (sgn == wide_int::SIGNED)
+	    {
+	      if (((x ^ o0) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
+		*overflow = true;
+	    }
+	  else if (old_borrow)
+	    {
+	      if ((~o0) <= o1)
+		*overflow = true;
+	    }
+	  else
+	    {
+	      if ((~o0) < o1)
+		*overflow = true;
+	    }
+	}
+      else
+	{
+	  if (sgn == wide_int::UNSIGNED)
+	    {
+	      /* The caveat for unsigned is to get rid of the bits above
+		 the precision before doing the addition.  To check the
+		 overflow, clear these bits and then redo the last
+		 addition.  If there are any non zero bits above the prec,
+		 we overflowed. */
+	      o0 = zext_hwi (o0, small_prec);
+	      o1 = zext_hwi (o1, small_prec);
+	      x = o0 - o1 - old_borrow;
+	      if (x >> small_prec)
+		*overflow = true;
+	    }
+	  else 
+	    {
+	      /* Overflow in this case is easy since we can see bits beyond
+		 the precision.  If the value computed is not the sign
+		 extended value, then we have overflow.  */
+	      unsigned HOST_WIDE_INT y = sext_hwi (x, small_prec);
+	      if (x != y)
+		*overflow = true;
+	    }
+	}
+    }
+
+  result.canonize ();
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wvww ("wide_int:: %s %d = (%s -O %s)\n", 
+		result, *overflow, *this, op1);
+#endif
+  return result;
+}
+
+/*
+ * Division and Mod
+ */
+
+/* Compute B_QUOTIENT and B_REMAINDER from B_DIVIDEND/B_DIVISOR.  The
+   algorithm is a small modification of the algorithm in Hacker's
+   Delight by Warren, which itself is a small modification of Knuth's
+   algorithm.  M is the number of significant elements of U however
+   there needs to be at least one extra element of B_DIVIDEND
+   allocated, N is the number of elements of B_DIVISOR.  */
+
+void
+wide_int::divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+			     unsigned HOST_HALF_WIDE_INT *b_remainder,
+			     unsigned HOST_HALF_WIDE_INT *b_dividend, 
+			     unsigned HOST_HALF_WIDE_INT *b_divisor, 
+			     int m, int n)
+{
+  /* The "digits" are a HOST_HALF_WIDE_INT which the size of half of a
+     HOST_WIDE_INT and stored in the lower bits of each word.  This
+     algorithm should work properly on both 32 and 64 bit
+     machines.  */
+  unsigned HOST_WIDE_INT b
+    = (unsigned HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT;
+  unsigned HOST_WIDE_INT qhat;   /* Estimate of quotient digit.  */
+  unsigned HOST_WIDE_INT rhat;   /* A remainder.  */
+  unsigned HOST_WIDE_INT p;      /* Product of two digits.  */
+  HOST_WIDE_INT s, i, j, t, k;
+
+  /* Single digit divisor.  */
+  if (n == 1)
+    {
+      k = 0;
+      for (j = m - 1; j >= 0; j--)
+	{
+	  b_quotient[j] = (k * b + b_dividend[j])/b_divisor[0];
+	  k = ((k * b + b_dividend[j])
+	       - ((unsigned HOST_WIDE_INT)b_quotient[j]
+		  * (unsigned HOST_WIDE_INT)b_divisor[0]));
+	}
+      b_remainder[0] = k;
+      return;
+    }
+
+  s = clz_hwi (b_divisor[n-1]) - HOST_BITS_PER_HALF_WIDE_INT; /* CHECK clz */
+
+  /* Normalize B_DIVIDEND and B_DIVISOR.  Unlike the published
+     algorithm, we can overwrite b_dividend and b_divisor, so we do
+     that.  */
+  for (i = n - 1; i > 0; i--)
+    b_divisor[i] = (b_divisor[i] << s)
+      | (b_divisor[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_divisor[0] = b_divisor[0] << s;
+
+  b_dividend[m] = b_dividend[m-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s);
+  for (i = m - 1; i > 0; i--)
+    b_dividend[i] = (b_dividend[i] << s)
+      | (b_dividend[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_dividend[0] = b_dividend[0] << s;
+
+  /* Main loop.  */
+  for (j = m - n; j >= 0; j--)
+    {
+      qhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) / b_divisor[n-1];
+      rhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) - qhat * b_divisor[n-1];
+    again:
+      if (qhat >= b || qhat * b_divisor[n-2] > b * rhat + b_dividend[j+n-2])
+	{
+	  qhat -= 1;
+	  rhat += b_divisor[n-1];
+	  if (rhat < b)
+	    goto again;
+	}
+
+      /* Multiply and subtract.  */
+      k = 0;
+      for (i = 0; i < n; i++)
+	{
+	  p = qhat * b_divisor[i];
+	  t = b_dividend[i+j] - k - (p & HALF_INT_MASK);
+	  b_dividend[i + j] = t;
+	  k = ((p >> HOST_BITS_PER_HALF_WIDE_INT)
+	       - (t >> HOST_BITS_PER_HALF_WIDE_INT));
+	}
+      t = b_dividend[j+n] - k;
+      b_dividend[j+n] = t;
+
+      b_quotient[j] = qhat;
+      if (t < 0)
+	{
+	  b_quotient[j] -= 1;
+	  k = 0;
+	  for (i = 0; i < n; i++)
+	    {
+	      t = (HOST_WIDE_INT)b_dividend[i+j] + b_divisor[i] + k;
+	      b_dividend[i+j] = t;
+	      k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	    }
+	  b_dividend[j+n] += k;
+	}
+    }
+  for (i = 0; i < n; i++)
+    b_remainder[i] = (b_dividend[i] >> s) 
+      | (b_dividend[i+1] << (HOST_BITS_PER_HALF_WIDE_INT - s));
+}
+
+
+/* Do a truncating divide DIVISOR into DIVIDEND.  The result is the
+   same size as the operands.  SIGN is either wide_int::SIGNED or
+   wide_int::UNSIGNED.  */
+
+wide_int
+wide_int::divmod_internal (bool compute_quotient, 
+			   const wide_int *dividend, 
+			   const HOST_WIDE_INT *divisor,
+			   unsigned int divisorlen,
+			   wide_int::SignOp sgn, wide_int *remainder,
+			   bool compute_remainder, 
+			   bool *oflow)
+{
+  wide_int quotient, u0, u1;
+  unsigned int prec = dividend->get_precision();
+  int blocks_needed = 2 * BLOCKS_NEEDED (prec);
+  /* The '2' in the next 4 vars are because they are built on half
+     sized wide ints.  */
+  unsigned HOST_HALF_WIDE_INT 
+    b_quotient[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_remainder[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_dividend[(MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT) + 1];
+  unsigned HOST_HALF_WIDE_INT
+    b_divisor[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  int m, n;
+  bool dividend_neg = false;
+  bool divisor_neg = false;
+  bool overflow = false;
+
+  if (divisor[0] == 0 && divisorlen == 1)
+    overflow = true;
+
+  /* The smallest signed number / -1 causes overflow.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      wide_int t = wide_int::set_bit_in_zero (prec - 1, prec);
+      if (*dividend == t && divisor[0] == -1 && divisorlen == 1)
+	overflow = true;
+    }
+
+  quotient.precision = prec;
+  remainder->precision = prec;
+
+  /* If overflow is set, just get out.  There will only be grief by
+     continuing.  */
+  if (overflow)
+    {
+      if (compute_remainder)
+	{
+	  remainder->len = 1;
+	  remainder->val[0] = 0;
+	}
+      if (oflow != 0)
+	*oflow = true;
+      return wide_int::zero (prec);
+    }
+
+  /* Do it on the host if you can.  */
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      quotient.len = 1;
+      remainder->len = 1;
+      if (sgn == wide_int::SIGNED)
+	{
+	  quotient.val[0] 
+	    = sext_hwi (dividend->val[0] / divisor[0], prec);
+	  remainder->val[0] 
+	    = sext_hwi (dividend->val[0] % divisor[0], prec);
+	}
+      else
+	{
+	  unsigned HOST_WIDE_INT o0 = dividend->val[0];
+	  unsigned HOST_WIDE_INT o1 = divisor[0];
+
+	  if (prec < HOST_BITS_PER_WIDE_INT)
+	    {
+	      o0 = zext_hwi (o0, prec);
+	      o1 = zext_hwi (o1, prec);
+	    }
+	  quotient.val[0] = sext_hwi (o0 / o1, prec);
+	  remainder->val[0] = sext_hwi (o0 % o1, prec);
+	}
+
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwwa ("wide_int:: (q = %s) (r = %s) = (%s / %s)\n", 
+		    quotient, *remainder, *dividend, divisor, divisorlen);
+#endif
+      return quotient;
+    }
+
+  /* Make the divisor and divident positive and remember what we
+     did.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      if (dividend->sign_mask ())
+	{
+	  u0 = dividend->neg ();
+	  dividend = &u0;
+	  dividend_neg = true;
+	}
+      if (divisor[divisorlen - 1] < 0)
+	{
+	  u1 = wide_int::zero (dividend->precision).sub_large (divisor, divisorlen);
+	  divisor = u1.val;
+	  divisorlen = u1.len;
+	  divisor_neg = true;
+	}
+    }
+
+  wi_unpack (b_dividend, (const unsigned HOST_WIDE_INT*)dividend->val,
+	     dividend->len, blocks_needed);
+  wi_unpack (b_divisor, (const unsigned HOST_WIDE_INT*)divisor, 
+	     divisorlen, blocks_needed);
+
+  if (dividend->sign_mask ())
+    m = blocks_needed;
+  else
+    m = 2 * dividend->get_len ();
+
+  if (SIGN_MASK (divisor[divisorlen - 1]))
+    n = blocks_needed;
+  else
+    n = 2 * divisorlen;
+
+  /* It is known that the top input block to the divisor is non zero,
+     but when this block is split into two half blocks, it may be that
+     the top half block is zero.  Skip over this half block.  */
+  if (b_divisor[n - 1] == 0)
+    n--;
+
+  divmod_internal_2 (b_quotient, b_remainder, b_dividend, b_divisor, m, n);
+
+  if (compute_quotient)
+    {
+      wi_pack ((unsigned HOST_WIDE_INT*)quotient.val, b_quotient, m);
+      quotient.len = m / 2;
+      quotient.canonize ();
+      /* The quotient is neg if exactly one of the divisor or dividend is
+	 neg.  */
+      if (dividend_neg != divisor_neg)
+	quotient = quotient.neg ();
+    }
+  else
+    quotient = wide_int::zero (dividend->precision);
+
+  if (compute_remainder)
+    {
+      wi_pack ((unsigned HOST_WIDE_INT*)remainder->val, b_remainder, n);
+      if (n & 1)
+	n++;
+      remainder->len = n / 2;
+      (*remainder).canonize ();
+      /* The remainder is always the same sign as the dividend.  */
+      if (dividend_neg)
+	*remainder = (*remainder).neg ();
+    }
+  else
+    *remainder = wide_int::zero (dividend->precision);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwwa ("wide_int:: (q = %s) (r = %s) = (%s / %s)\n", 
+		quotient, *remainder, *dividend, divisor, divisorlen);
+#endif
+  return quotient;
+}
+
+
+/*
+ * Shifting, rotating and extraction.
+ */
+
+/* Extract WIDTH bits from THIS starting at OFFSET.  The result is
+   assumed to fit in a HOST_WIDE_INT.  This function is safe in that
+   it can properly access elements that may not be explicitly
+   represented.  */
+
+HOST_WIDE_INT
+wide_int::extract_to_hwi (int offset, int width) const
+{
+  int start_elt, end_elt, shift;
+  HOST_WIDE_INT x;
+
+  /* Get rid of the easy cases first.   */
+  if (offset >= len * HOST_BITS_PER_WIDE_INT)
+    return sign_mask ();
+  if (offset + width <= 0)
+    return 0;
+
+  shift = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset < 0)
+    {
+      start_elt = -1;
+      end_elt = 0;
+      x = 0;
+    }
+  else
+    {
+      start_elt = offset / HOST_BITS_PER_WIDE_INT;
+      end_elt = (offset + width - 1) / HOST_BITS_PER_WIDE_INT;
+      x = start_elt >= len 
+	? sign_mask ()
+	: (unsigned HOST_WIDE_INT)val[start_elt] >> shift;
+    }
+
+  if (start_elt != end_elt)
+    {
+      HOST_WIDE_INT y = end_elt == len
+	? sign_mask () : val[end_elt];
+
+      x |= y << (HOST_BITS_PER_WIDE_INT - shift);
+    }
+
+  if (width != HOST_BITS_PER_WIDE_INT)
+    x &= ((HOST_WIDE_INT)1 << width) - 1;
+
+  return x;
+}
+
+
+/* Left shift THIS by CNT.  See the definition of Op.TRUNC for how to
+   set Z.  Since this is used internally, it has the ability to
+   specify the BISIZE and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+wide_int
+wide_int::lshift_large (unsigned int cnt, unsigned int res_prec) const
+{
+  wide_int result;
+  unsigned int i;
+
+  result.precision = res_prec;
+
+  if (cnt >= res_prec)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+      return result;
+    }
+
+  for (i = 0; i < res_prec; i += HOST_BITS_PER_WIDE_INT)
+    result.val[i / HOST_BITS_PER_WIDE_INT]
+      = extract_to_hwi (i - cnt, HOST_BITS_PER_WIDE_INT);
+
+  result.len = BLOCKS_NEEDED (res_prec);
+  result.canonize ();
+
+  return result;
+}
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set Z.  */
+
+wide_int
+wide_int::rshiftu_large (unsigned int cnt) const
+{
+  wide_int result;
+  int stop_block, offset, i;
+
+  result.precision = precision;
+
+  if (cnt >= precision)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  offset = (precision - cnt) & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset)
+    result.val[stop_block - 1] = zext_hwi (result.val[stop_block - 1], offset);
+  else
+    /* The top block had a 1 at the top position so it will decompress
+       wrong unless a zero block is added.  This only works because we
+       know the shift was greater than 0.  */
+    if (result.val[stop_block - 1] < 0)
+      result.val[result.len++] = 0;
+  return result;
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set Z.  */
+
+wide_int
+wide_int::rshifts_large (unsigned int cnt) const
+{
+  wide_int result;
+  int stop_block, i;
+
+  result.precision = precision;
+
+  if (cnt >= precision)
+    {
+      HOST_WIDE_INT m = sign_mask ();
+      result.val[0] = m;
+      result.len = 1;
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  /* No need to sign extend the last block, since it extract_to_hwi
+     already did that.  */
+  return result;
+}
+
+/*
+ * Private utilities.
+ */
+/* Decompress THIS for at least TARGET bits into a result with
+   precision PREC.  */
+
+wide_int
+wide_int::decompress (unsigned int target, unsigned int prec) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (target);
+  HOST_WIDE_INT mask;
+  int len, i;
+
+  result.precision = prec;
+  result.len = blocks_needed;
+
+  for (i = 0; i < this->len; i++)
+    result.val[i] = val[i];
+
+  len = this->len;
+
+  if (target > result.precision)
+    return result;
+
+  /* The extension that we are doing here is not sign extension, it is
+     decompression.  */
+  mask = sign_mask ();
+  while (len < blocks_needed)
+    result.val[len++] = mask;
+
+  return result;
+}
+
+/*
+ * Private debug printing routines.
+ */
+
+/* The debugging routines print results of wide operations into the
+   dump files of the respective passes in which they were called.  */
+static char *
+dumpa (const HOST_WIDE_INT *val, unsigned int len, char *buf)
+{
+  int i;
+  int l;
+  const char * sep = "";
+
+  l = sprintf (buf, "[(");
+  for (i = len - 1; i >= 0; i--)
+    {
+      l += sprintf (&buf[l], "%s" HOST_WIDE_INT_PRINT_HEX, sep, val[i]);
+      sep = " ";
+    }
+
+  gcc_assert (len != 0);
+
+  l += sprintf (&buf[l], ")]");
+
+  gcc_assert (l < MAX_SIZE);
+  return buf;
+
+
+}
+
+/* The debugging routines print results of wide operations into the
+   dump files of the respective passes in which they were called.  */
+char *
+wide_int::dump (char* buf) const
+{
+  int i;
+  int l;
+  const char * sep = "";
+
+  l = sprintf (buf, "[%d (", precision);
+  for (i = len - 1; i >= 0; i--)
+    {
+      l += sprintf (&buf[l], "%s" HOST_WIDE_INT_PRINT_HEX, sep, val[i]);
+      sep = " ";
+    }
+
+  gcc_assert (len != 0);
+
+  l += sprintf (&buf[l], ")]");
+
+  gcc_assert (l < MAX_SIZE);
+  return buf;
+}
+
+#ifdef DEBUG_WIDE_INT
+void
+wide_int::debug_vw (const char* fmt, int r, const wide_int& o0)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r, o0.dump (buf0));
+}
+
+void
+wide_int::debug_vwh (const char* fmt, int r, const wide_int &o0,
+		     HOST_WIDE_INT o1)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r, o0.dump (buf0), o1);
+}
+
+void
+wide_int::debug_vwa (const char* fmt, int r, const wide_int &o0,
+		     const HOST_WIDE_INT *o1, unsigned int l1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r, o0.dump (buf0), dumpa (o1, l1, buf1));
+}
+
+void
+wide_int::debug_vww (const char* fmt, int r, const wide_int &o0,
+		     const wide_int &o1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r, o0.dump (buf0), o1.dump (buf1));
+}
+
+void
+wide_int::debug_wh (const char* fmt, const wide_int &r,
+		    HOST_WIDE_INT o1)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o1);
+}
+
+void
+wide_int::debug_whh (const char* fmt, const wide_int &r,
+		     HOST_WIDE_INT o1, HOST_WIDE_INT o2)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o1, o2);
+}
+
+void
+wide_int::debug_wv (const char* fmt, const wide_int &r, int v0)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0);
+}
+
+void
+wide_int::debug_wvv (const char* fmt, const wide_int &r,
+		     int v0, int v1)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0, v1);
+}
+
+void
+wide_int::debug_wvvv (const char* fmt, const wide_int &r,
+		      int v0, int v1, int v2)
+{
+  char buf0[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0, v1, v2);
+}
+
+void
+wide_int::debug_wvwa (const char* fmt, const wide_int &r, int v0,
+		      const wide_int &o0, const HOST_WIDE_INT *o1,
+		      unsigned int o1len)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0,
+	   o0.dump (buf1), dumpa (o1, o1len, buf2));
+}
+
+void
+wide_int::debug_wvww (const char* fmt, const wide_int &r, int v0,
+		      const wide_int &o0, const wide_int &o1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), v0,
+	   o0.dump (buf1), o1.dump (buf2));
+}
+
+void
+wide_int::debug_ww (const char* fmt, const wide_int &r,
+		    const wide_int &o0)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1));
+}
+
+void
+wide_int::debug_wwa (const char* fmt, const wide_int &r,
+		     const wide_int &o0, const HOST_WIDE_INT *o1, 
+		     unsigned int l1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1), dumpa (o1, l1, buf2));
+}
+
+void
+wide_int::debug_wwv (const char* fmt, const wide_int &r,
+		     const wide_int &o0, int v0)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1), v0);
+}
+
+void
+wide_int::debug_wwvs (const char* fmt, const wide_int &r, 
+		      const wide_int &o0, int v0,
+		      const char *s)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1), v0, s);
+}
+
+void
+wide_int::debug_wwvvs (const char* fmt, const wide_int &r, 
+		       const wide_int &o0, int v0, int v1,
+		       const char *s)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0), o0.dump (buf1), v0, v1, s);
+}
+
+void
+wide_int::debug_wwwvv (const char* fmt, const wide_int &r,
+		       const wide_int &o0, const wide_int &o1,
+		       int v0, int v1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), v0, v1);
+}
+
+void
+wide_int::debug_www (const char* fmt, const wide_int &r,
+		     const wide_int &o0, const wide_int &o1)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2));
+}
+
+void
+wide_int::debug_wwwa (const char* fmt, const wide_int &r,
+		      const wide_int &o0, const wide_int &o1,
+		      const HOST_WIDE_INT *o2, unsigned int o2len)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  char buf3[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), dumpa (o2, o2len, buf3));
+}
+
+void
+wide_int::debug_wwww (const char* fmt, const wide_int &r,
+		      const wide_int &o0, const wide_int &o1,
+		      const wide_int &o2)
+{
+  char buf0[MAX_SIZE];
+  char buf1[MAX_SIZE];
+  char buf2[MAX_SIZE];
+  char buf3[MAX_SIZE];
+  fprintf (dump_file, fmt, r.dump (buf0),
+	   o0.dump (buf1), o1.dump (buf2), o2.dump (buf3));
+}
+
+#endif
+
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
new file mode 100644
index 0000000..c12db4a
--- /dev/null
+++ b/gcc/wide-int.h
@@ -0,0 +1,2608 @@
+/* Operations with very long integers.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef WIDE_INT_H
+#define WIDE_INT_H
+
+/* A wide integer is currently represented as a vector of
+   HOST_WIDE_INTs.  The vector contains enough elements to hold a
+   value of MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT which is
+   a derived for each host target combination.  The values are stored
+   in the vector with the least signicant HOST_BITS_PER_WIDE_INT bits
+   of the value stored in element 0.
+
+   A wide_int contains three fields: the vector (VAL), precision and a
+   length, (LEN).  The length is the number of HWIs needed to
+   represent the value.
+
+   Since most integers used in a compiler are small values, it is
+   generally profitable to use a representation of the value that is
+   shorter than the modes precision.  LEN is used to indicate the
+   number of elements of the vector that are in use.  When LEN *
+   HOST_BITS_PER_WIDE_INT < the precision, the value has been
+   compressed.  The values of the elements of the vector greater than
+   LEN - 1. are all equal to the highest order bit of LEN.
+
+   The representation does not contain any information inherant about
+   signedness of the represented value, so it can be used to represent
+   both signed and unsigned numbers.   For operations where the results
+   depend on signedness (division, comparisons), the signedness must
+   be specified separately.  For operations where the signness
+   matters, one of the operands to the operation specifies either
+   wide_int::SIGNED or wide_int::UNSIGNED.
+
+   The numbers are stored as sign entended numbers as a means of
+   compression.  Leading HOST_WIDE_INTS that contain strings of either
+   -1 or 0 are removed as long as they can be reconstructed from the
+   top bit that is being represented.
+
+   All constructors for wide_int take either a precision, an enum
+   machine_mode or tree_type.  */
+
+
+#ifndef GENERATOR_FILE
+#include "tree.h"
+#include "system.h"
+#include "hwint.h"
+#include "options.h"
+#include "tm.h"
+#include "insn-modes.h"
+#include "machmode.h"
+#include "double-int.h"
+#include <gmp.h>
+#include "dumpfile.h"
+#include "real.h"
+
+#define DEBUG_WIDE_INT
+
+#define WIDE_INT_MAX_ELTS \
+  ((4 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+
+class wide_int {
+  /* Internal representation.  */
+  
+  /* VAL is set to a size that is capable of computing a full
+     multiplication on the largest mode that is represented on the
+     target.  The full multiplication is use by tree-vrp.  tree-vpn
+     currently does a 2x largest mode by 2x largest mode yielding a 4x
+     largest mode result.  If operations are added that require larger
+     buffers, then VAL needs to be changed.  */
+  HOST_WIDE_INT val[WIDE_INT_MAX_ELTS];
+  unsigned short len;
+  unsigned int precision;
+
+ public:
+  enum ShiftOp {
+    NONE,
+    /* There are two uses for the wide-int shifting functions.  The
+       first use is as an emulation of the target hardware.  The
+       second use is as service routines for other optimizations.  The
+       first case needs to be identified by passing TRUNC as the value
+       of ShiftOp so that shift amount is properly handled according to the
+       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
+       amount is always truncated by the bytesize of the mode of
+       THIS.  */
+    TRUNC
+  };
+
+  enum SignOp {
+    /* Many of the math functions produce different results depending
+       on if they are SIGNED or UNSIGNED.  In general, there are two
+       different functions, whose names are prefixed with an 'S" and
+       or an 'U'.  However, for some math functions there is also a
+       routine that does not have the prefix and takes an SignOp
+       parameter of SIGNED or UNSIGNED.  */
+    SIGNED,
+    UNSIGNED
+  };
+
+  /* Conversions.  */
+
+  static wide_int from_shwi (HOST_WIDE_INT op0, 
+			     unsigned int precision, bool *overflow = 0);
+  static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+			     unsigned int precision, bool *overflow = 0);
+
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type, 
+				   bool *overflow = 0);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+				    bool *overflow = 0);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+				    enum machine_mode mode, 
+				    bool *overflow = 0);
+  static wide_int from_array (const HOST_WIDE_INT* op0,
+			      unsigned int len, 
+			      unsigned int precision, bool need_canon = true); 
+  inline static wide_int from_array (const HOST_WIDE_INT* op0,
+				     unsigned int len,
+				     enum machine_mode mode);
+  inline static wide_int from_array (const HOST_WIDE_INT* op0,
+				     unsigned int len,
+				     const_tree type);
+
+  static wide_int from_double_int (double_int, 
+				   unsigned int precision);
+  inline static wide_int from_double_int (double_int, enum machine_mode);
+  static wide_int from_tree (const_tree);
+  static wide_int from_rtx (const_rtx, enum machine_mode);
+  static wide_int from_buffer (const unsigned char*, int);
+
+  inline HOST_WIDE_INT to_shwi (unsigned int prec = 0) const;
+  inline unsigned HOST_WIDE_INT to_uhwi (unsigned int prec = 0) const;
+
+  /* Largest and smallest values that are represented in modes or precisions.  */
+
+  static wide_int max_value (unsigned int prec, 
+			     unsigned int precision, SignOp sgn);
+  inline static wide_int max_value (unsigned int precision, SignOp sgn);
+  inline static wide_int max_value (const_tree type);
+  inline static wide_int max_value (enum machine_mode mode, SignOp sgn);
+  
+  static wide_int min_value (unsigned int prec, 
+			     unsigned int precision, SignOp sgn);
+  inline static wide_int min_value (unsigned int precision, SignOp sgn);
+  inline static wide_int min_value (const_tree type);
+  inline static wide_int min_value (enum machine_mode mode, SignOp sgn);
+  
+  /* Small constants */
+
+  inline static wide_int minus_one (unsigned int prec);
+  inline static wide_int zero (unsigned int prec);
+  inline static wide_int one (unsigned int prec);
+  inline static wide_int two (unsigned int prec);
+
+  /* Accessors.  */
+
+  inline unsigned short get_len () const;
+  inline unsigned int get_precision () const;
+  inline HOST_WIDE_INT elt (unsigned int i) const;
+
+  /* Printing functions.  */
+
+  void print_dec (char *buf, SignOp sgn) const;
+  void print_dec (FILE *file, SignOp sgn) const;
+  void print_decs (char *buf) const;
+  void print_decs (FILE *file) const;
+  void print_decu (char *buf) const;
+  void print_decu (FILE *file) const;
+  void print_hex (char *buf) const;
+  void print_hex (FILE *file) const;
+
+  /* Comparative functions.  */
+
+  inline bool minus_one_p () const;
+  inline bool zero_p () const;
+  inline bool one_p () const;
+  inline bool neg_p () const;
+
+  template <typename T>
+    inline bool operator == (T c) const;
+  
+  template <typename T>
+    inline bool operator != (T c) const;
+  
+  template <typename T>
+    inline bool gt_p (T c, SignOp sgn) const;
+  template <typename T>
+    inline bool gts_p (T c) const;
+  template <typename T>
+    inline bool gtu_p (T c) const;
+  
+  template <typename T>
+    inline bool lt_p (T c, SignOp sgn) const;
+  template <typename T>
+    inline bool lts_p (T c) const;
+  template <typename T>
+    inline bool ltu_p (T c) const;
+  
+  template <typename T>
+    inline int cmp (T c, SignOp sgn) const;
+  template <typename T>
+    inline int cmps (T c) const;
+  template <typename T>
+    inline int cmpu (T c) const;
+  
+  bool only_sign_bit_p (unsigned int prec) const;
+  inline bool only_sign_bit_p () const;
+  inline bool fits_uhwi_p () const;
+  inline bool fits_shwi_p () const;
+  bool fits_to_tree_p (const_tree type) const;
+  bool fits_u_p (unsigned int prec) const;
+  bool fits_s_p (unsigned int prec) const;
+
+  /* Min and max */
+
+  template <typename T>
+    inline wide_int min (T c, SignOp sgn) const;
+    inline wide_int min (const wide_int &op1, SignOp sgn) const;
+  template <typename T>
+    inline wide_int max (T c, SignOp sgn) const;
+    inline wide_int max (const wide_int &op1, SignOp sgn) const;
+  template <typename T>
+    inline wide_int smin (T c) const;
+    inline wide_int smin (const wide_int &op1) const;
+  template <typename T>
+    inline wide_int smax (T c) const;
+    inline wide_int smax (const wide_int &op1) const;
+  template <typename T>
+    inline wide_int umin (T c) const;
+    inline wide_int umin (const wide_int &op1) const;
+  template <typename T>
+    inline wide_int umax (T c) const;
+    inline wide_int umax (const wide_int &op1) const;
+
+  /* Extension, these do not change the precision.  */
+
+  inline wide_int ext (unsigned int offset, SignOp sgn) const;
+  wide_int sext (unsigned int offset) const;
+  wide_int zext (unsigned int offset) const;
+
+  /* Make a fast copy.  */
+
+  wide_int copy () const;
+
+  /* These change the underlying precision.  */
+  
+  wide_int force_to_size (unsigned int precision, SignOp sgn) const;
+  inline wide_int force_to_size (enum machine_mode mode, SignOp sgn) const;
+  inline wide_int force_to_size (const_tree type) const;
+  inline wide_int force_to_size (const_tree type, SignOp sgn) const;
+
+  inline wide_int sforce_to_size (enum machine_mode mode) const;
+  inline wide_int sforce_to_size (const_tree type) const;
+  inline wide_int zforce_to_size (enum machine_mode mode) const;
+  inline wide_int zforce_to_size (const_tree type) const;
+
+  /* Masking, and Insertion  */
+
+  wide_int set_bit (unsigned int bitpos) const;
+  static wide_int set_bit_in_zero (unsigned int bitpos, unsigned int prec);
+  inline static wide_int set_bit_in_zero (unsigned int, 
+					  enum machine_mode mode);
+  inline static wide_int set_bit_in_zero (unsigned int, const_tree type);
+  wide_int insert (const wide_int &op0, unsigned int offset,
+		   unsigned int width) const;
+
+  wide_int bswap () const;
+
+  static wide_int mask (unsigned int start, bool negate, 
+			unsigned int prec);
+  inline static wide_int mask (unsigned int start, bool negate, 
+			       enum machine_mode mode);
+  inline static wide_int mask (unsigned int start, bool negate,
+			       const_tree type);
+
+  static wide_int shifted_mask (unsigned int start, unsigned int width,
+				bool negate, unsigned int prec);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, enum machine_mode mode);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, const_tree type);
+
+  inline HOST_WIDE_INT sign_mask () const;
+
+  /* Logicals */
+
+  template <typename T>
+    inline wide_int operator & (T c) const;
+  template <typename T>
+    inline wide_int and_not (T c) const;
+  inline wide_int operator ~ () const;
+  template <typename T>
+    inline wide_int operator | (T c) const;
+  template <typename T>
+    inline wide_int or_not (T c) const;
+  template <typename T>
+    inline wide_int operator ^ (T c) const;
+  
+  /* Arithmetic operation functions, alpha sorted.  */
+  
+  wide_int abs () const;
+  template <typename T>
+    inline wide_int operator + (T c) const;
+  wide_int add (const wide_int &x, SignOp sgn, bool *overflow) const;
+  
+  wide_int clz () const;
+  wide_int clrsb () const;
+  wide_int ctz () const;
+  wide_int exact_log2 () const;
+  wide_int floor_log2 () const;
+  wide_int ffs () const;
+  
+  template <typename T>
+    inline wide_int operator * (T c) const;
+  template <typename T>
+    inline wide_int mul (T c, SignOp sgn, bool *overflow) const;
+  template <typename T>
+    inline wide_int smul (T c, bool *overflow) const;
+  template <typename T>
+    inline wide_int umul (T c, bool *overflow) const;
+  template <typename T>
+    inline wide_int mul_full (T c, SignOp sgn) const;
+  template <typename T>
+    inline wide_int smul_full (T c) const;
+  template <typename T>
+    inline wide_int umul_full (T c) const;
+  template <typename T>
+    inline wide_int mul_high (T c, SignOp sgn) const;
+  
+  inline wide_int neg () const;
+  inline wide_int neg (bool *overflow) const;
+  
+  wide_int parity () const;
+  wide_int popcount () const;
+  
+  template <typename T>
+    inline wide_int operator - (T c) const;
+  wide_int sub (const wide_int &x, SignOp sgn, bool *overflow) const;
+  
+  /* Divison and mod.  These are the ones that are actually used, but
+     there are a lot of them.  */
+  
+  template <typename T>
+    inline wide_int div_trunc (T c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+    inline wide_int sdiv_trunc (T c) const;
+  template <typename T>
+    inline wide_int udiv_trunc (T c) const;
+  
+  template <typename T>
+    inline wide_int div_floor (T c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+    inline wide_int udiv_floor (T c) const;
+  template <typename T>
+    inline wide_int sdiv_floor (T c) const;
+  template <typename T>
+    inline wide_int div_ceil (T c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+    inline wide_int div_round (T c, SignOp sgn, bool *overflow = 0) const;
+  
+  template <typename T>
+    inline wide_int divmod_trunc (T c, wide_int *mod, SignOp sgn) const;
+  template <typename T>
+    inline wide_int sdivmod_trunc (T c, wide_int *mod) const;
+  template <typename T>
+    inline wide_int udivmod_trunc (T c, wide_int *mod) const;
+  
+  template <typename T>
+    inline wide_int divmod_floor (T c, wide_int *mod, SignOp sgn) const;
+  template <typename T>
+    inline wide_int sdivmod_floor (T c, wide_int *mod) const;
+  
+  template <typename T>
+    inline wide_int mod_trunc (T c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+    inline wide_int smod_trunc (T c) const;
+  template <typename T>
+    inline wide_int umod_trunc (T c) const;
+  
+  template <typename T>
+    inline wide_int mod_floor (T c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+    inline wide_int umod_floor (T c) const;
+  template <typename T>
+    inline wide_int mod_ceil (T c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+    inline wide_int mod_round (T c, SignOp sgn, bool *overflow = 0) const;
+  
+  /* Shifting rotating and extracting.  */
+  HOST_WIDE_INT extract_to_hwi (int offset, int width) const;
+  
+  template <typename T>
+    inline wide_int lshift (T c, unsigned int bitsize = 0,
+			    unsigned int precision = 0,
+			    ShiftOp z = NONE) const;
+
+  template <typename T>
+    inline wide_int lrotate (T c) const;
+  inline wide_int lrotate (unsigned HOST_WIDE_INT y) const;
+
+  template <typename T>
+    inline wide_int rshift (T c, SignOp sgn, 
+			    unsigned int bitsize = 0,
+			    ShiftOp z = NONE) const;
+  template <typename T>
+    inline wide_int rshiftu (T c, unsigned int bitsize = 0,
+			     ShiftOp z = NONE) const;
+  template <typename T>
+    inline wide_int rshifts (T c, unsigned int bitsize = 0,
+			     ShiftOp z = NONE) const;
+
+  template <typename T>
+    inline wide_int rrotate (T c) const;
+    inline wide_int rrotate (unsigned HOST_WIDE_INT y) const;
+
+  static const int DUMP_MAX = (2 * (MAX_BITSIZE_MODE_ANY_INT / 4
+			       + MAX_BITSIZE_MODE_ANY_INT 
+				    / HOST_BITS_PER_WIDE_INT + 32));
+  char *dump (char* buf) const;
+ private:
+
+  /* 
+   * Internal versions that do the work if the values do not fit in a
+   * HWI.
+   */ 
+
+  /* Comparisons */
+  bool eq_p_large (const HOST_WIDE_INT *, unsigned int) const;
+  static bool lts_p_large (const HOST_WIDE_INT *, unsigned int, 
+			   const HOST_WIDE_INT *, unsigned int,
+			   unsigned int);
+  int cmps_large (const HOST_WIDE_INT *, unsigned int) const;
+  static bool ltu_p_large (const HOST_WIDE_INT *, unsigned int, 
+			   const HOST_WIDE_INT *, unsigned int);
+  int cmpu_large (const HOST_WIDE_INT *, unsigned int) const;
+
+  /* Logicals.  */
+  wide_int and_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int and_not_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int or_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int or_not_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int xor_large (const HOST_WIDE_INT *, unsigned int) const;
+
+  /* Arithmetic */
+  wide_int add_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int sub_large (const HOST_WIDE_INT *, unsigned int) const;
+
+  wide_int lshift_large (unsigned int cnt, unsigned int res_prec) const;
+  wide_int rshiftu_large (unsigned int cnt) const;
+  wide_int rshifts_large (unsigned int cnt) const;
+
+  static wide_int
+    mul_internal (bool high, bool full, 
+		  const wide_int *op1, const HOST_WIDE_INT *op2, unsigned int op2len,
+		  wide_int::SignOp sgn,  bool *overflow, bool needs_overflow);
+  static void
+    divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+		       unsigned HOST_HALF_WIDE_INT *b_remainder,
+		       unsigned HOST_HALF_WIDE_INT *b_dividend, 
+		       unsigned HOST_HALF_WIDE_INT *b_divisor, 
+		       int m, int n);
+  static wide_int
+    divmod_internal (bool compute_quotient, 
+		     const wide_int *dividend, const HOST_WIDE_INT *, unsigned int,
+		     wide_int::SignOp sgn, wide_int *remainder,
+		     bool compute_remainder, 
+		     bool *overflow);
+
+
+  /* Private utility routines.  */
+  wide_int decompress (unsigned int target, unsigned int precision) const;
+  void canonize ();
+  static inline int trunc_shift (const HOST_WIDE_INT *cnt, unsigned int len, 
+				 unsigned int bitsize, ShiftOp z);
+
+  /* The following template and its overrides are used for the second
+     operand of binary functions.  They access the value are package
+     it so that the operation can be done.  These have been
+     implemented so that pointer copying is done from the rep of the
+     second operand rather than actual data copying.  This is safe
+     even for garbage collected objects since the value is immediately
+     throw away.  
+
+     The first two templates match all integers.  */
+
+  template <typename T>
+  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int *l, T x)
+  { 
+    s[0] = x;
+    if (~(T)0 < (T)0
+	|| sizeof (T) < sizeof (HOST_WIDE_INT))
+      {
+	*l = 1;
+      }
+    else
+      {
+	s[1] = 0;
+	*l = 2;	  
+      }
+    return s;
+  }
+  
+  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s ATTRIBUTE_UNUSED,
+					int *l, const wide_int &y)
+  {
+    *l = y.len;
+    return y.val;
+  }
+
+  /* This overload may just return the pointer to the value and set
+     the length.  */
+  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int *l, const_tree tcst)
+  {
+    /* This is rather complex now, in the future when the rep for tree
+       cst is changed, it will be just a pointer and len copy.  */
+    tree type = TREE_TYPE (tcst);
+    unsigned int prec = TYPE_PRECISION (type);
+
+    if (prec == HOST_BITS_PER_DOUBLE_INT 
+	&& TYPE_UNSIGNED (type)
+	&& TREE_INT_CST_HIGH (tcst) < 0)
+      {
+	/* Copy the result because it does not fit in two HWIs.  */
+	s[0] = TREE_INT_CST_LOW (tcst);
+	s[1] = TREE_INT_CST_HIGH (tcst);
+	s[2] = 0;
+	*l = 3;
+	return s;
+      }
+    else
+      {
+	if (prec > HOST_BITS_PER_WIDE_INT)
+	  *l = 2;
+	else
+	  {
+	    if (prec == HOST_BITS_PER_WIDE_INT
+		&& TYPE_UNSIGNED (type)
+		&& (HOST_WIDE_INT)TREE_INT_CST_LOW (tcst) < 0)
+	      *l = 2;
+	    else
+	      *l = 1;
+	  }
+	return (const HOST_WIDE_INT*)&TREE_INT_CST_LOW (tcst);
+      }
+  }
+
+  /* There should logically be an overload for rtl here, but it cannot
+     be here because of circular include issues.  It is in rtl.h.  */
+  static inline const HOST_WIDE_INT* to_shwi2 
+    (HOST_WIDE_INT *s ATTRIBUTE_UNUSED, int *l, rtx rcst);
+
+#ifdef DEBUG_WIDE_INT
+  /* Debugging routines.  */
+  static void debug_vw  (const char* fmt, int r, const wide_int& o0);
+  static void debug_vwh (const char* fmt, int r, const wide_int &o0,
+			 HOST_WIDE_INT o1);
+  static void debug_vwa (const char* fmt, int r, const wide_int &o0,
+			 const HOST_WIDE_INT *, unsigned int v0);
+  static void debug_vww (const char* fmt, int r, const wide_int &o0,
+			 const wide_int &o1);
+  static void debug_wh (const char* fmt, const wide_int &r,
+			 HOST_WIDE_INT o1);
+  static void debug_whh (const char* fmt, const wide_int &r,
+			 HOST_WIDE_INT o1, HOST_WIDE_INT o2);
+  static void debug_wv (const char* fmt, const wide_int &r, int v0);
+  static void debug_wvv (const char* fmt, const wide_int &r, int v0,
+			 int v1);
+  static void debug_wvvv (const char* fmt, const wide_int &r, int v0,
+			  int v1, int v2);
+  static void debug_wvwa (const char* fmt, const wide_int &r, int v0,
+			  const wide_int &o0, const HOST_WIDE_INT *o1, 
+			  unsigned int o1l);
+  static void debug_wvww (const char* fmt, const wide_int &r, int v0,
+			  const wide_int &o0, const wide_int &o1);
+  static void debug_wwa (const char* fmt, const wide_int &r,
+			 const wide_int &o0, const HOST_WIDE_INT *, 
+			 unsigned int v0);
+  static void debug_wwv (const char* fmt, const wide_int &r,
+			 const wide_int &o0, int v0);
+  static void debug_wwvs (const char* fmt, const wide_int &r, 
+			  const wide_int &o0, 
+			  int v0, const char *s);
+  static void debug_wwvvs (const char* fmt, const wide_int &r, 
+			   const wide_int &o0, 
+			   int v0, int v1, const char *s);
+  static void debug_wwwvv (const char* fmt, const wide_int &r,
+			   const wide_int &o0, const wide_int &o1,
+			   int v0, int v1);
+  static void debug_ww (const char* fmt, const wide_int &r,
+			const wide_int &o0);
+  static void debug_www (const char* fmt, const wide_int &r,
+			 const wide_int &o0, const wide_int &o1);
+  static void debug_wwwa (const char* fmt, const wide_int &r,
+			  const wide_int &o0, const wide_int &o1, 
+			  const HOST_WIDE_INT *o2, unsigned int len);
+  static void debug_wwww (const char* fmt, const wide_int &r,
+			  const wide_int &o0, const wide_int &o1, 
+			  const wide_int &o2);
+#endif
+};
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with precision
+   taken from MODE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, enum machine_mode mode)
+{
+  return wide_int::set_bit_in_zero (bitpos, GET_MODE_PRECISION (mode));
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with precision
+   taken from TYPE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, const_tree type)
+{
+
+  return wide_int::set_bit_in_zero (bitpos, TYPE_PRECISION (type));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with precision
+   taken from MODE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, enum machine_mode mode)
+{
+  return wide_int::mask (width, negate, GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with precision
+   taken from TYPE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, const_tree type)
+{
+
+  return wide_int::mask (width, negate, TYPE_PRECISION (type));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the bits
+   above that up to the precision are zeros.  The result is inverted
+   if NEGATE is true.  The result is made with precision taken from
+   MODE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, enum machine_mode mode)
+{
+  return wide_int::shifted_mask (start, width, negate,
+				 GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the bits
+   above that up to the precision are zeros.  The result is inverted
+   if NEGATE is true.  The result is made with precision taken from
+   TYPE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, const_tree type)
+{
+
+  return wide_int::shifted_mask (start, width, negate,
+				 TYPE_PRECISION (type));
+}
+
+/* Produce 0 or -1 that is the smear of the sign bit.  */
+
+HOST_WIDE_INT
+wide_int::sign_mask () const
+{
+  int i = len - 1;
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
+	    >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* VRP appears to be badly broken and this is a very ugly fix.  */
+  if (i >= 0)
+    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
+
+  gcc_unreachable ();
+#if 0
+  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
+#endif
+}
+
+/* Conversions */
+
+/* Convert OP0 into a wide_int with parameters taken from TYPE.  If
+   the value does not fit, set OVERFLOW.  */
+
+wide_int
+wide_int::from_hwi (HOST_WIDE_INT op0, const_tree type, 
+		    bool *overflow)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return wide_int::from_uhwi (op0, prec, overflow);
+  else
+    return wide_int::from_shwi (op0, prec, overflow);
+}
+
+/* Convert signed OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+		     bool *overflow)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_shwi (op0, prec, overflow);
+}
+
+/* Convert unsigned OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode, 
+		     bool *overflow)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_uhwi (op0, prec, overflow);
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec == 0)
+    prec = precision;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = sext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec == 0)
+    prec = precision;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = zext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+
+/* Convert OP0 of LEN into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT* op0, unsigned int len, 
+		      enum machine_mode mode)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_array (op0, len, prec);
+}
+
+/* Convert OP0 of LEN into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT* op0, unsigned int len, 
+		      const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return wide_int::from_array (op0, len, prec);
+}
+
+/* Convert double_int OP0 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_double_int (double_int op0, enum machine_mode mode)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_double_int (op0, prec);
+}
+
+/* Min and Max value helpers.  */
+
+/* Produce the largest SGNed number that is represented in PRECISION.
+   The result is represented in PRECISION.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (unsigned int precision, SignOp sgn)
+{
+  return max_value (precision, precision, sgn);
+}
+  
+/* Produce the largest number that is represented in MODE. The
+   precision are taken from mode.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (enum machine_mode mode, SignOp sgn)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+  return max_value (prec, prec, sgn);
+}
+
+/* Produce the largest number that is represented in TYPE. The
+   precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::max_value (const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  return max_value (prec, prec, TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+/* Produce the smallest SGNed number that is represented in PRECISION.
+   The result is represented in PRECISION.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::min_value (unsigned int precision, SignOp sgn)
+{
+  return min_value (precision, precision, sgn);
+}
+  
+/* Produce the smallest number that is represented in MODE. The
+   precision are taken from mode.  SGN must be SIGNED or UNSIGNED.  */
+
+wide_int
+wide_int::min_value (enum machine_mode mode, SignOp sgn)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+  return min_value (prec, prec, sgn);
+}
+
+/* Produce the smallest number that is represented in TYPE. The
+   precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::min_value (const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  return min_value (prec, prec, TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+
+/* Small constants.  */
+
+/* Return a wide int of -1 with precision PREC.  */
+
+wide_int
+wide_int::minus_one (unsigned int prec)
+{
+  return wide_int::from_shwi (-1, prec);
+}
+
+/* Return a wide int of 0 with precision PREC.  */
+
+wide_int
+wide_int::zero (unsigned int prec)
+{
+  return wide_int::from_shwi (0, prec);
+}
+
+/* Return a wide int of 1 with precision PREC.  */
+
+wide_int
+wide_int::one (unsigned int prec)
+{
+  return wide_int::from_shwi (1, prec);
+}
+
+/* Return a wide int of 2 with precision PREC.  */
+
+wide_int
+wide_int::two (unsigned int prec)
+{
+  return wide_int::from_shwi (2, prec);
+}
+
+/* Public accessors for the interior of a wide int.  */
+
+/* Get the number of host wide ints actually represented within the
+   wide int.  */
+
+unsigned short
+wide_int::get_len () const
+{
+  return len;
+}
+
+/* Get precision of the value represented within the wide int.  */
+
+unsigned int
+wide_int::get_precision () const
+{
+  return precision;
+}
+
+/* Get a particular element of the wide int.  */
+
+HOST_WIDE_INT
+wide_int::elt (unsigned int i) const
+{
+  return i >= len ? sign_mask () : val[i];
+}
+
+/* Return true if THIS is -1.  */
+
+bool
+wide_int::minus_one_p () const
+{
+  return len == 1 && val[0] == (HOST_WIDE_INT)-1;
+}
+
+/* Return true if THIS is 0.  */
+
+bool
+wide_int::zero_p () const
+{
+  return len == 1 && val[0] == 0;
+}
+
+/* Return true if THIS is 1.  */
+
+bool
+wide_int::one_p () const
+{
+  return len == 1 && val[0] == 1;
+}
+
+/* Return true if THIS is negative.  */
+
+bool
+wide_int::neg_p () const
+{
+  return sign_mask () != 0;
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently signed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+template <typename T>
+bool
+wide_int::operator == (T c) const
+{
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << precision) - 1;
+      result = (val[0] & mask) == (s[0] & mask);
+    }
+  else if (precision == HOST_BITS_PER_WIDE_INT)
+      result = val[0] == s[0];
+  else
+    result = eq_p_large (s, cl);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwa ("wide_int:: %d = (%s == %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+/* Return true if THIS is not equal to OP1. */ 
+
+template <typename T>
+bool
+wide_int::operator != (T c) const
+{
+  return !(*this == c);
+}  
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+template <typename T>
+bool
+wide_int::lt_p (T c, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (c);
+  else
+    return ltu_p (c);
+}  
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+template <typename T>
+bool
+wide_int::lts_p (T c) const
+{
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    /* The values are already logically sign extended.  */
+    result = val[0] < s[0];
+  else
+    result = lts_p_large (val, len, s, cl, precision);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwa ("wide_int:: %d = (%s lts_p %s\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+template <typename T>
+bool
+wide_int::ltu_p (T c) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (s[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = s[0];
+	}
+
+      result = x0 < x1;
+    }
+  else
+    result = ltu_p_large (val, len, s, cl);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwa ("wide_int:: %d = (%s ltu_p %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+template <typename T>
+bool
+wide_int::gt_p (T c, SignOp op) const
+{
+  if (op == SIGNED)
+    return gts_p (c);
+  else
+    return gtu_p (c);
+}  
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+template <typename T>
+bool
+wide_int::gts_p (T c) const
+{
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] > s[0];
+    }
+  else
+    /* Reverse the parms and use ltu.  */
+    result = lts_p_large (s, cl, val, len, precision);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwa ("wide_int:: %d = (%s gts_p %s\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+template <typename T>
+bool
+wide_int::gtu_p (T c) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (s[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = s[0];
+	}
+
+      result = x0 > x1;
+    }
+  else 
+    /* Reverse the parms and use ltu.  */
+    result = ltu_p_large (s, cl, val, len);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwa ("wide_int:: %d = (%s gtu_p %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+
+/* Return -1 0 or 1 depending on how THIS compares with OP1.  Signness
+   is indicated by OP.  */
+
+template <typename T>
+int
+wide_int::cmp (T c, SignOp op) const
+{
+  if (op == SIGNED)
+    return cmps (c);
+  else
+    return cmpu (c);
+}  
+
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+template <typename T>
+int
+wide_int::cmps (T c) const
+{
+  int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      if (val[0] < s[0])
+	result = -1;
+      else if (val[0] > s[0])
+	result = 1;
+      else 
+	result = 0;
+    }
+  else
+    result = cmps_large (s, cl);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwa ("wide_int:: %d = (%s cmps %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+template <typename T>
+int
+wide_int::cmpu (T c) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (s[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = s[0];
+	}
+
+      if (x0 < x1)
+	result = -1;
+      else if (x0 == x1)
+	result = 0;
+      else
+	result = 1;
+    }
+  else
+    result = cmpu_large (s, cl);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_vwa ("wide_int:: %d = (%s cmpu %s)\n", result, *this, s, cl);
+#endif
+
+  return result;
+}
+
+
+/* Return the signed or unsigned min of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::min (T c, SignOp sgn) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (sgn == SIGNED)
+    return lts_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+  else
+    return ltu_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the signed or unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::min (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return lts_p (op1) ? (*this) : op1;
+  else
+    return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed or unsigned max of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::max (T c, SignOp sgn) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (sgn == SIGNED)
+    return gts_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+  else
+    return gtu_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the signed or unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::max (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return gts_p (op1) ? (*this) : op1;
+  else
+    return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed min of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::smin (T c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return lts_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the signed min of THIS and OP1. */
+
+wide_int
+wide_int::smin (const wide_int &op1) const
+{
+  return lts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed max of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::smax (T c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return gts_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the signed max of THIS and OP1. */
+
+wide_int
+wide_int::smax (const wide_int &op1) const
+{
+  return gts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned min of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::umin (T c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return ltu_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::umin (const wide_int &op1) const
+{
+  return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned max of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::umax (T c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return gtu_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::umax (const wide_int &op1) const
+{
+  return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p () const
+{
+  return only_sign_bit_p (precision);
+}
+
+/* Return true if THIS fits in a HOST_WIDE_INT with no loss of
+   precision.  */
+
+bool
+wide_int::fits_shwi_p () const
+{
+  return len == 1;
+}
+
+/* Return true if THIS fits in an unsigned HOST_WIDE_INT with no loss
+   of precision.  */
+
+bool
+wide_int::fits_uhwi_p () const
+{
+  return len == 1 
+    || (len == 2 && val[1] == 0);
+}
+
+/* Return THIS extended to PREC.  The signness of the extension is
+   specified by OP.  */
+
+wide_int 
+wide_int::ext (unsigned int prec, SignOp z) const
+{
+  if (z == UNSIGNED)
+    return zext (prec);
+  else
+    return sext (prec);
+}
+
+/* Return THIS forced to the precision of TYPE.  If this is extension,
+   the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (enum machine_mode mode, SignOp sgn) const
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (prec, sgn);
+}
+
+/* Return THIS forced to the precision and sign of TYPE.  If this is
+   extension, the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (const_tree type) const
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  SignOp sgn = TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED;
+
+  return force_to_size (prec, sgn);
+}
+
+/* Return THIS zero extended to the precision of TYPE but extends
+   using SGN.  If this is extension, the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (const_tree type, SignOp sgn) const
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (prec, sgn);
+}
+
+/* Return THIS forced to the precision of TYPE.  If this is extension,
+   it is signed. */
+
+wide_int 
+wide_int::sforce_to_size (enum machine_mode mode) const
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (prec, SIGNED);
+}
+
+/* Return THIS zero extended to the precision of TYPE but extends
+   using SGN.  If this is extension, it is signed. */
+
+wide_int 
+wide_int::sforce_to_size (const_tree type) const
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (prec, SIGNED);
+}
+
+/* Return THIS forced to the precision of TYPE.  If this
+   is extension, it is unsigned. */
+
+wide_int 
+wide_int::zforce_to_size (enum machine_mode mode) const
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (prec, UNSIGNED);
+}
+
+/* Return THIS zero extended to the precision of TYPE but extends
+   using SGN.  If this is extension, it is unsigned. */
+
+wide_int 
+wide_int::zforce_to_size (const_tree type) const
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (prec, UNSIGNED);
+}
+
+/*
+ * Logicals.
+ */
+
+/* Return THIS & OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator & (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] & s[0];
+    }
+  else
+    result = and_large (s, cl);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwa ("wide_int:: %s = (%s & %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+
+/* Return THIS & ~OP1.  */
+
+template <typename T>
+wide_int
+wide_int::and_not (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] & ~s[0];
+    }
+  else
+    result = and_not_large (s, cl);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwa ("wide_int:: %s = (%s &~ %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+
+/* Return the logical negation (bitwise complement) of THIS.  */
+
+wide_int
+wide_int::operator ~ () const
+{
+  wide_int result;
+  int l0 = len - 1;
+
+  result.len = len;
+  result.precision = precision;
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = ~val[l0];
+      l0--;
+    }
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_ww ("wide_int:: %s = (~ %s)\n", result, *this);
+#endif
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator | (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] | s[0];
+    }
+  else
+    result = or_large (s, cl);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwa ("wide_int:: %s = (%s | %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+
+/* Return THIS | ~OP1.  */
+
+template <typename T>
+wide_int
+wide_int::or_not (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] | ~s[0];
+    }
+  else
+    result = or_not_large (s, cl);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwa ("wide_int:: %s = (%s |~ %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+
+/* Return THIS ^ OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator ^ (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] ^ s[0];
+    }
+  else
+    result = xor_large (s, cl);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwa ("wide_int:: %s = (%s ^ %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+/*
+ * Integer arithmetic
+ */
+
+/* Return THIS + OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator + (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] + s[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = add_large (s, cl);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwa ("wide_int:: %s = (%s + %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+/* Multiply THIS and OP1.  The result is the same precision as the
+   operands, so there is no reason for signed or unsigned
+   versions.  */
+
+template <typename T>
+wide_int
+wide_int::operator * (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+  bool overflow = false;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] * s[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = mul_internal (false, false, this, s, cl, UNSIGNED, &overflow, false);
+#ifdef DEBUG_WIDE_INT
+      if (dump_file)
+	debug_wwa ("wide_int:: %s = (%s * %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.
+   OVERFLOW is set true if the result overflows.  */
+
+template <typename T>
+wide_int 
+wide_int::mul (T c, SignOp sgn, bool *overflow) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return mul_internal (false, false, this, s, cl, sgn, overflow, true);
+}
+
+/* Signed multiply THIS and OP1.  The result is the same precision as
+   the operands.  OVERFLOW is set true if the result overflows.  */
+
+template <typename T>
+wide_int
+wide_int::smul (T c, bool *overflow) const
+{
+  return mul (c, SIGNED, overflow);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is the same precision
+   as the operands.  OVERFLOW is set true if the result overflows.  */
+
+template <typename T>
+wide_int
+wide_int::umul (T c, bool *overflow) const
+{
+  return mul (c, UNSIGNED, overflow);
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.  The
+   result is twice the precision as the operands.  The signess is
+   specified with SGN.  */
+
+template <typename T>
+wide_int
+wide_int::mul_full (T c, SignOp sgn) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return mul_internal (false, true, this, s, cl, sgn, 0, false);
+}
+
+/* Signed multiply THIS and OP1.  The result is twice the precision as
+   the operands.  */
+
+template <typename T>
+wide_int
+wide_int::smul_full (T c) const
+{
+  return mul_full (c, SIGNED);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is twice the precision
+   as the operands.  */
+
+template <typename T>
+wide_int
+wide_int::umul_full (T c) const
+{
+  return mul_full (c, UNSIGNED);
+}
+
+/* Multiply THIS and OP1 and return the high part of that result.  The
+   signess is specified with SGN.  The result is the same precision as
+   the operands.  The mode is the same mode as the operands.  The
+   signess is specified with y.  */
+
+template <typename T>
+wide_int
+wide_int::mul_high (T c, SignOp sgn) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  return mul_internal (true, false, this, s, cl, sgn, 0, false);
+}
+
+/* Negate THIS.  */
+
+wide_int
+wide_int::neg () const
+{
+  wide_int z = wide_int::from_shwi (0, precision);
+  return z - *this;
+}
+
+/* Negate THIS.  Set overflow if the value cannot be negated.  */
+
+wide_int
+wide_int::neg (bool *overflow) const
+{
+  wide_int z = wide_int::from_shwi (0, precision);
+  if (only_sign_bit_p ())
+    *overflow = true;
+
+  return z - *this;
+}
+
+/* Return THIS - OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator - (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] - s[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = sub_large (s, cl);
+  
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwa ("wide_int:: %s = (%s - %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is truncated.
+   Overflow is set to true if the result overflows, otherwise it is
+   not set.  */
+template <typename T>
+wide_int
+wide_int::div_trunc (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  
+  return divmod_internal (true, this, s, cl, sgn, 
+			  &remainder, false, overflow);
+}
+
+/* Signed divide with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::sdiv_trunc (T c) const
+{
+  return div_trunc (c, SIGNED);
+}
+
+/* Unsigned divide with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::udiv_trunc (T c) const
+{
+  return div_trunc (c, UNSIGNED);
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is floor
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::div_floor (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return quotient - 1;
+  return quotient;
+}
+
+/* Unsigned divide with floor truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::udiv_floor (T c) const
+{
+  bool overflow;
+
+  return div_floor (c, UNSIGNED, &overflow);
+}
+
+/* Signed divide with floor truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::sdiv_floor (T c) const
+{
+  bool overflow;
+
+  return div_floor (c, SIGNED, &overflow);
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is ceil
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::div_ceil (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return quotient;
+      else
+	return quotient + 1;
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is round
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::div_round (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+  if (!remainder.zero_p ())
+    {
+      wide_int divisor = wide_int::from_array (s, cl, precision);
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu_large (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return quotient - 1;
+	      else 
+		return quotient + 1;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu_large (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return quotient + 1;
+	}
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing both the quotient and remainder.
+   The result is the same size as the operands.  The sign is specified
+   in SGN.  The output is truncated.  */
+
+template <typename T>
+wide_int
+wide_int::divmod_trunc (T c, wide_int *remainder, SignOp sgn) const
+{
+  bool overflow = false;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return divmod_internal (true, this, s, cl, sgn, 
+			  remainder, true, &overflow);
+}
+
+/* Signed divide/mod with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::sdivmod_trunc (T c, wide_int *mod) const
+{
+  return divmod_trunc (c, mod, SIGNED);
+}
+
+/* Unsigned divide/mod with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::udivmod_trunc (T c, wide_int *mod) const
+{
+  return divmod_trunc (c, mod, UNSIGNED);
+}
+
+/* Divide DIVISOR into THIS.  The remainder is also produced in
+   REMAINDER.  The result is the same size as the operands.  The sign
+   is specified in SGN.  The output is floor truncated.  Overflow is
+   set to true if the result overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::divmod_floor (T c, wide_int *remainder, SignOp sgn) const
+{
+  wide_int quotient;
+  bool overflow = false;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      remainder, true, &overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !(*remainder).zero_p ())
+    {
+      *remainder = *remainder - wide_int::from_array (s, cl, precision);
+      return quotient - 1;
+    }
+  return quotient;
+}
+
+/* Signed divide/mod with floor truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::sdivmod_floor (T c, wide_int *mod) const
+{
+  return divmod_floor (c, mod, SIGNED);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::mod_trunc (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  divmod_internal (true, this, s, cl, sgn, 
+			  &remainder, true, overflow);
+  return remainder;
+}
+
+/* Signed mod with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::smod_trunc (T c) const
+{
+  return mod_trunc (c, SIGNED);
+}
+
+/* Unsigned mod with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::umod_trunc (T c) const
+{
+  return mod_trunc (c, UNSIGNED);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is floor truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::mod_floor (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return remainder - wide_int::from_array (s, cl, precision);
+  return remainder;
+}
+
+/* Unsigned mod with floor truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::umod_floor (T c) const
+{
+  bool overflow;
+
+  return mod_floor (c, UNSIGNED, &overflow);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is the
+   same size as the operands.  The sign is specified in SGN.  The
+   output is ceil truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::mod_ceil (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return remainder;
+      else
+	return remainder - wide_int::from_array (s, cl, precision);
+    }
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is round truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::mod_round (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      wide_int divisor = wide_int::from_array (s, cl, precision);
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu_large (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return remainder + divisor;
+	      else 
+		return remainder - divisor;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu_large (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return remainder - divisor;
+	}
+    }
+  return remainder;
+}
+
+
+/* If SHIFT_COUNT_TRUNCATED is defined, truncate CNT.   
+
+   At first look, the shift truncation code does not look right.
+   Shifts (and rotates) are done according to the precision of the
+   mode but the shift count is truncated according to the bitsize of
+   the mode.  This is how real hardware works (Knuth's mix machine is
+   the only known exception to this rule, but it was never real).
+
+   On an ideal machine, like Knuth's mix machine, a shift count is a
+   word long and all of the bits of that word are examined to compute
+   the shift amount.  But on real hardware, especially on machines
+   with fast (single cycle shifts) that takes too long.  On these
+   machines, the amount of time to perform a shift dictates the cycle
+   time of the machine so corners are cut to keep this fast.  A
+   comparison of an entire 64 bit word would take something like 6
+   gate delays before the shifting can even start.
+
+   So real hardware only looks at a small part of the shift amount.
+   On ibm machines, this tends to be 1 more than what is necessary to
+   encode the shift amount.  The rest of the world looks at only the
+   minimum number of bits.  This means that only 3 gate delays are
+   necessary to set up the shifter.
+
+   On the other hand, right shifts and rotates must be according to
+   the precision or the operation does not make any sense. 
+
+   This function is called in two contexts.  If OP == TRUNC, this
+   function provides a count that matches the semantics of the target
+   machine depending on the value of SHIFT_COUNT_TRUNCATED.  Note that
+   if SHIFT_COUNT_TRUNCATED is not defined, this function may produce
+   -1 as a value if the shift amount is greater than the bitsize of
+   the mode.  -1 is a surrogate for a very large amount.
+
+   If OP == NONE, then this function always truncates the shift value
+   to the bitsize because this shifting operation is a function that
+   is internal to GCC.  */
+
+inline int
+wide_int::trunc_shift (const HOST_WIDE_INT *cnt, unsigned int len ATTRIBUTE_UNUSED,
+		       unsigned int bitsize, ShiftOp trunc_op)
+{
+  if (trunc_op == TRUNC)
+    {
+      gcc_checking_assert (bitsize != 0);
+#ifdef SHIFT_COUNT_TRUNCATED
+      return cnt[0] & (bitsize - 1);
+#else
+      if (cnt[0] < bitsize && cnt[0] >= 0 && len == 1)
+	return cnt[0];
+      else 
+	return -1;
+#endif
+    }
+  else if (bitsize == 0)
+    return cnt[0];
+  else
+    return cnt[0] & (bitsize - 1);
+}
+
+/* Left shift THIS by C.  See the definition of Op.TRUNC for how to
+   set TRUNC_OP.  Since this is used internally, it has the ability to
+   specify the BITSIZE  and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+template <typename T>
+wide_int
+wide_int::lshift (T c, unsigned int bitsize, 
+		  unsigned int res_prec, ShiftOp trunc_op) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+  HOST_WIDE_INT shift;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (res_prec == 0)
+    res_prec = precision;
+
+  shift = trunc_shift (s, cl, bitsize, trunc_op);
+  if (shift == -1)
+    result = wide_int::zero (precision);
+  else if (shift == 0 && res_prec == precision)
+    result = *this;
+  /* Handle the simple case quickly.   */
+  else if (res_prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.precision = res_prec;
+      result.len = 1;
+      result.val[0] = val[0] << shift;
+    }
+  else
+    result = lshift_large (shift, res_prec);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwa ("wide_int:: %s = (%s << %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+/* Rotate THIS left by Y within its precision.  */
+
+template <typename T>
+wide_int
+wide_int::lrotate (T c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return lrotate ((unsigned HOST_WIDE_INT)s[0]);
+}
+
+
+/* Rotate THIS left by CNT within its precision.  */
+
+wide_int
+wide_int::lrotate (unsigned HOST_WIDE_INT cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (cnt);
+  right = rshiftu (precision - cnt);
+  result = left | right;
+
+  return result;
+}
+
+
+/* Right shift THIS by Y.  SGN indicates the sign.  TRUNC_OP indicates the
+   truncation option.  */
+
+template <typename T>
+wide_int
+wide_int::rshift (T c, SignOp sgn, 
+		  unsigned int bitsize, ShiftOp trunc_op) const
+{
+  if (sgn == UNSIGNED)
+    return rshiftu (c, bitsize, trunc_op);
+  else
+    return rshifts (c, bitsize, trunc_op);
+}
+
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set TRUNC_OP.  */
+
+template <typename T>
+wide_int
+wide_int::rshiftu (T c, unsigned int bitsize,
+		   ShiftOp trunc_op) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+  HOST_WIDE_INT shift;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  shift = trunc_shift (s, cl, bitsize, trunc_op);
+  
+  if (shift == 0)
+    result = copy ();
+  else if (shift == -1)
+    result = wide_int::zero (precision);
+  else if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* Handle the simple case quickly.   */
+      unsigned HOST_WIDE_INT x = val[0];
+
+      result.precision = precision;
+      result.len = 1;
+
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	x = zext_hwi (x, precision);
+
+      result.val[0] = x >> shift;
+    }
+  else 
+    result = rshiftu_large (shift);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwa ("wide_int:: %s = (%s >>U %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set TRUNC_OP.  */
+
+template <typename T>
+wide_int
+wide_int::rshifts (T c, unsigned int bitsize,
+		   ShiftOp trunc_op) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+  HOST_WIDE_INT shift;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  shift = trunc_shift (s, cl, bitsize, trunc_op);
+  
+  if (shift == 0)
+    result = copy ();
+  else if (shift == -1)
+    result = wide_int::zero (precision);
+  else if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* Handle the simple case quickly.   */
+      HOST_WIDE_INT x = val[0];
+
+      result.precision = precision;
+      result.len = 1;
+      result.val[0] = x >> shift;
+    }
+  else 
+    result = rshifts_large (shift);
+
+#ifdef DEBUG_WIDE_INT
+  if (dump_file)
+    debug_wwa ("wide_int:: %s = (%s >>S %s)\n", result, *this, s, cl);
+#endif
+  return result;
+}
+
+/* Rotate THIS right by Y within its precision.  */
+
+
+template <typename T>
+wide_int
+wide_int::rrotate (T c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return rrotate ((unsigned HOST_WIDE_INT) s[0]);
+}
+
+
+/* Rotate THIS left by CNT within its precision.  */
+
+wide_int
+wide_int::rrotate (unsigned HOST_WIDE_INT cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (precision - cnt);
+  right = rshiftu (cnt);
+  result = left | right;
+
+  return result;
+}
+
+/* tree related routines.  */
+
+extern tree wide_int_to_tree (tree type, const wide_int &cst);
+extern tree wide_int_to_infinite_tree (tree type, const wide_int &cst, 
+				       unsigned int prec);
+extern tree force_fit_type_wide (tree, const wide_int &, int, bool);
+
+/* real related routines.  */
+extern wide_int real_to_integer (const REAL_VALUE_TYPE *, bool *, int);
+extern wide_int decimal_real_to_integer (const REAL_VALUE_TYPE *, bool *, int);
+
+
+/* Conversion to and from GMP integer representations.  */
+
+void mpz_set_wide_int (mpz_t, wide_int, bool);
+wide_int mpz_get_wide_int (const_tree, mpz_t, bool);
+#endif /* GENERATOR FILE */
+
+#endif /* WIDE_INT_H */

[-- Attachment #3: p4-6.clog --]
[-- Type: text/plain, Size: 243 bytes --]

2013-04-16  Kenneth Zadeck <zadeck@naturalbridge.com>

	* Makefile.in (wide-int.c, wide-int.h): New files.
	* wide-int.c: New file containing implementation of wide_int class.
	* wide-int.h: New file containing public spec for wide_int class.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-17  0:49                                                                                 ` Kenneth Zadeck
@ 2013-04-17  3:41                                                                                   ` Kenneth Zadeck
  2013-04-24 13:25                                                                                     ` Richard Biener
  2013-04-17  7:34                                                                                   ` patch to fix constant math - builtins.c - the first of the tree level patches for wide-int Kenneth Zadeck
                                                                                                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-17  3:41 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 218 bytes --]

Here is a refreshed version of the rtl changes for wide-int.   the only 
change from the previous versions is that the wide-int binary operations 
have been simplified to use the new wide-int binary templates.

kenny


[-- Attachment #2: p5-6.clog --]
[-- Type: text/plain, Size: 4479 bytes --]

2013-04-16  Kenneth Zadeck <zadeck@naturalbridge.com>

	* alias.c  (rtx_equal_for_memref_p): Fixed comment.
	* builtins.c (c_getstr, c_readstr, expand_builtin_signbit): 
	Make to work with any size int.
	* combine.c (try_combine, subst): Changed to support any 
	size integer.
	* coretypes.h (hwivec_def, hwivec, const_hwivec): New.
	* cse.c (hash_rtx_cb): Added CONST_WIDE_INT case are
	modified DOUBLE_INT case.
	* cselib.c (rtx_equal_for_cselib_1): Converted cases to 
	CASE_CONST_UNIQUE.
	(cselib_hash_rtx): Added CONST_WIDE_INT case.
	* defaults.h (TARGET_SUPPORTS_WIDE_INT): New.
	* doc/rtl.texi (CONST_DOUBLE, CONST_WIDE_INT): Updated.
	* doc/tm.texi (TARGET_SUPPORTS_WIDE_INT): New.	
	* doc/tm.texi.in (TARGET_SUPPORTS_WIDE_INT): New.
	* dojump.c (prefer_and_bit_test): Use wide int api.
	* dwarf2out.c (get_full_len): New function.
	(dw_val_equal_p, size_of_loc_descr,
	output_loc_operands, print_die, attr_checksum, same_dw_val_p,
	size_of_die, value_format, output_die, mem_loc_descriptor,
	loc_descriptor, extract_int, add_const_value_attribute,
	hash_loc_operands, compare_loc_operands): Add support for wide-ints.
	(add_AT_wide): New function.
	* dwarf2out.h (enum dw_val_class): Added dw_val_class_wide_int.
	* emit-rtl.c (const_wide_int_htab): Add marking.
	(const_wide_int_htab_hash, const_wide_int_htab_eq,
	lookup_const_wide_int, immed_wide_int_const): New functions.
	(const_double_htab_hash, const_double_htab_eq,
	rtx_to_double_int, immed_double_const): Conditionally 
	changed CONST_DOUBLE behavior.
 	(immed_double_const, init_emit_once): Changed to support wide-int.
	* explow.c (plus_constant): Now uses wide-int api.
	* expmed.c (mask_rtx, lshift_value): Now uses wide-int.
 	(expand_mult, expand_smod_pow2): Make to work with any size int.
	(make_tree): Added CONST_WIDE_INT case.
	* expr.c (convert_modes): Added support for any size int.
	(emit_group_load_1): Added todo for place that still does not
	allow large ints.
	(store_expr, expand_constructor): Fixed comments.
	(expand_expr_real_2, expand_expr_real_1,
	reduce_to_bit_field_precision, const_vector_from_tree):
	Converted to use wide-int api.
	* final.c (output_addr_const): Added CONST_WIDE_INT case.
	* genemit.c (gen_exp): Added CONST_WIDE_INT case.
	* gengenrtl.c (excluded_rtx): Added CONST_WIDE_INT case.
	* gengtype.c (wide-int): New type.
	* genpreds.c (write_one_predicate_function): Fixed comment.
	(add_constraint): Added CONST_WIDE_INT test.
	(write_tm_constrs_h): Do not emit hval or lval if target
	supports wide integers.
	* gensupport.c (std_preds): Added const_wide_int_operand and
	const_scalar_int_operand.
	* optabs.c (expand_subword_shift, expand_doubleword_shift,
	expand_absneg_bit, expand_absneg_bit, expand_copysign_absneg,
	expand_copysign_bit): Made to work with any size int.  
	* postreload.c (reload_cse_simplify_set):  Now uses wide-int api.
	* print-rtl.c (print_rtx): Added CONST_WIDE_INT case.
	* read-rtl.c (validate_const_wide_int): New function.
	(read_rtx_code): Added CONST_WIDE_INT case.
	* recog.c (const_scalar_int_operand, const_double_operand):
	New versions if target supports wide integers.
	(const_wide_int_operand): New function.
	* rtl.c (DEF_RTL_EXPR): Added CONST_WIDE_INT case.
	(rtx_size): Ditto.
	(rtx_alloc_stat, hwivec_output_hex, hwivec_check_failed_bounds):
	New functions.
	(iterative_hash_rtx): Added CONST_WIDE_INT case.
	* rtl.def (CONST_WIDE_INT): New.
	* rtl.h (hwivec_def): New function.
	(HWI_GET_NUM_ELEM, HWI_PUT_NUM_ELEM, CONST_WIDE_INT_P,
	CONST_SCALAR_INT_P, XHWIVEC_ELT, HWIVEC_CHECK, CONST_WIDE_INT_VEC,
	CONST_WIDE_INT_NUNITS, CONST_WIDE_INT_ELT, rtx_alloc_v): New macros.
	(chain_next): Added hwiv case.
	(CASE_CONST_SCALAR_INT, CONST_INT, CONST_WIDE_INT):  Added new
	defs if target supports wide ints.
	* rtlanal.c (commutative_operand_precedence, split_double):
	Added CONST_WIDE_INT case.
	* sched-vis.c (print_value): Added CONST_WIDE_INT case are
	modified DOUBLE_INT case.
	* sel-sched-ir.c (lhs_and_rhs_separable_p): Fixed comment
	* simplify-rtx.c (mode_signbit_p,
	simplify_const_unary_operation, simplify_binary_operation_1,
	simplify_const_binary_operation,
	simplify_const_relational_operation, simplify_immed_subreg):
	Make work with any size int.  .
	* tree-ssa-address.c (addr_for_mem_ref): Changes to use
	wide-int rather than double-int.
	* tree.c (wide_int_to_tree): New function.
	* var-tracking.c (loc_cmp): Added CONST_WIDE_INT case.
	* varasm.c (const_rtx_hash_1): Added CONST_WIDE_INT case.

[-- Attachment #3: p5-6.diff --]
[-- Type: text/x-patch, Size: 136530 bytes --]

diff --git a/gcc/alias.c b/gcc/alias.c
index ef11c6a..ed5ceb4 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -1471,9 +1471,7 @@ rtx_equal_for_memref_p (const_rtx x, const_rtx y)
 
     case VALUE:
     CASE_CONST_UNIQUE:
-      /* There's no need to compare the contents of CONST_DOUBLEs or
-	 CONST_INTs because pointer equality is a good enough
-	 comparison for these nodes.  */
+      /* Pointer equality guarantees equality for these nodes.  */
       return 0;
 
     default:
diff --git a/gcc/builtins.c b/gcc/builtins.c
index efab82e..ed5a6b3 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -672,20 +672,24 @@ c_getstr (tree src)
   return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
 }
 
-/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
+/* Return a constant integer corresponding to target reading
    GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
 
 static rtx
 c_readstr (const char *str, enum machine_mode mode)
 {
-  HOST_WIDE_INT c[2];
+  wide_int c;
   HOST_WIDE_INT ch;
   unsigned int i, j;
+  HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  unsigned int len = (GET_MODE_PRECISION (mode) + HOST_BITS_PER_WIDE_INT - 1)
+    / HOST_BITS_PER_WIDE_INT;
+
+  for (i = 0; i < len; i++)
+    tmp[i] = 0;
 
   gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
 
-  c[0] = 0;
-  c[1] = 0;
   ch = 1;
   for (i = 0; i < GET_MODE_SIZE (mode); i++)
     {
@@ -696,13 +700,14 @@ c_readstr (const char *str, enum machine_mode mode)
 	  && GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
 	j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
       j *= BITS_PER_UNIT;
-      gcc_assert (j < HOST_BITS_PER_DOUBLE_INT);
 
       if (ch)
 	ch = (unsigned char) str[i];
-      c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
+      tmp[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
     }
-  return immed_double_const (c[0], c[1], mode);
+  
+  c = wide_int::from_array (tmp, len, mode);
+  return immed_wide_int_const (c, mode);
 }
 
 /* Cast a target constant CST to target CHAR and if that value fits into
@@ -4994,12 +4999,12 @@ expand_builtin_signbit (tree exp, rtx target)
 
   if (bitpos < GET_MODE_BITSIZE (rmode))
     {
-      double_int mask = double_int_zero.set_bit (bitpos);
+      wide_int mask = wide_int::set_bit_in_zero (bitpos, rmode);
 
       if (GET_MODE_SIZE (imode) > GET_MODE_SIZE (rmode))
 	temp = gen_lowpart (rmode, temp);
       temp = expand_binop (rmode, and_optab, temp,
-			   immed_double_int_const (mask, rmode),
+			   immed_wide_int_const (mask, rmode),
 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
   else
diff --git a/gcc/combine.c b/gcc/combine.c
index 6d58b19..bfa151d 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -2669,23 +2669,15 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
 	    offset = -1;
 	}
 
-      if (offset >= 0
-	  && (GET_MODE_PRECISION (GET_MODE (SET_DEST (temp)))
-	      <= HOST_BITS_PER_DOUBLE_INT))
+      if (offset >= 0)
 	{
-	  double_int m, o, i;
+	  wide_int o;
 	  rtx inner = SET_SRC (PATTERN (i3));
 	  rtx outer = SET_SRC (temp);
-
-	  o = rtx_to_double_int (outer);
-	  i = rtx_to_double_int (inner);
-
-	  m = double_int::mask (width);
-	  i &= m;
-	  m = m.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
-	  i = i.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
-	  o = o.and_not (m) | i;
-
+	  
+	  o = (wide_int::from_rtx (outer, GET_MODE (SET_DEST (temp)))
+	       .insert (wide_int::from_rtx (inner, GET_MODE (dest)),
+			offset, width));
 	  combine_merges++;
 	  subst_insn = i3;
 	  subst_low_luid = DF_INSN_LUID (i2);
@@ -2696,8 +2688,8 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
 	  /* Replace the source in I2 with the new constant and make the
 	     resulting insn the new pattern for I3.  Then skip to where we
 	     validate the pattern.  Everything was set up above.  */
-	  SUBST (SET_SRC (temp),
-		 immed_double_int_const (o, GET_MODE (SET_DEST (temp))));
+	  SUBST (SET_SRC (temp), 
+		 immed_wide_int_const (o, GET_MODE (SET_DEST (temp))));
 
 	  newpat = PATTERN (i2);
 
@@ -5112,7 +5104,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
 		  if (! x)
 		    x = gen_rtx_CLOBBER (mode, const0_rtx);
 		}
-	      else if (CONST_INT_P (new_rtx)
+	      else if (CONST_SCALAR_INT_P (new_rtx)
 		       && GET_CODE (x) == ZERO_EXTEND)
 		{
 		  x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 320b4dd..3ea8920 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -55,6 +55,9 @@ typedef const struct rtx_def *const_rtx;
 struct rtvec_def;
 typedef struct rtvec_def *rtvec;
 typedef const struct rtvec_def *const_rtvec;
+struct hwivec_def;
+typedef struct hwivec_def *hwivec;
+typedef const struct hwivec_def *const_hwivec;
 union tree_node;
 typedef union tree_node *tree;
 typedef const union tree_node *const_tree;
diff --git a/gcc/cse.c b/gcc/cse.c
index f2c8f63..8e3bb88 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -2331,15 +2331,23 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
                + (unsigned int) INTVAL (x));
       return hash;
 
+    case CONST_WIDE_INT:
+      {
+	int i;
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hash += CONST_WIDE_INT_ELT (x, i);
+      }
+      return hash;
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
 	 the integers representing the constant.  */
       hash += (unsigned int) code + (unsigned int) GET_MODE (x);
-      if (GET_MODE (x) != VOIDmode)
-	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      else
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	hash += ((unsigned int) CONST_DOUBLE_LOW (x)
 		 + (unsigned int) CONST_DOUBLE_HIGH (x));
+      else
+	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       return hash;
 
     case CONST_FIXED:
@@ -3756,6 +3764,7 @@ equiv_constant (rtx x)
 
       /* See if we previously assigned a constant value to this SUBREG.  */
       if ((new_rtx = lookup_as_function (x, CONST_INT)) != 0
+	  || (new_rtx = lookup_as_function (x, CONST_WIDE_INT)) != 0
           || (new_rtx = lookup_as_function (x, CONST_DOUBLE)) != 0
           || (new_rtx = lookup_as_function (x, CONST_FIXED)) != 0)
         return new_rtx;
diff --git a/gcc/cselib.c b/gcc/cselib.c
index dcad9741..3f7c156 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -923,8 +923,7 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, enum machine_mode memmode)
   /* These won't be handled correctly by the code below.  */
   switch (GET_CODE (x))
     {
-    case CONST_DOUBLE:
-    case CONST_FIXED:
+    CASE_CONST_UNIQUE:
     case DEBUG_EXPR:
       return 0;
 
@@ -1118,15 +1117,23 @@ cselib_hash_rtx (rtx x, int create, enum machine_mode memmode)
       hash += ((unsigned) CONST_INT << 7) + INTVAL (x);
       return hash ? hash : (unsigned int) CONST_INT;
 
+    case CONST_WIDE_INT:
+      {
+	int i;
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hash += CONST_WIDE_INT_ELT (x, i);
+      }
+      return hash;
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
 	 the integers representing the constant.  */
       hash += (unsigned) code + (unsigned) GET_MODE (x);
-      if (GET_MODE (x) != VOIDmode)
-	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      else
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	hash += ((unsigned) CONST_DOUBLE_LOW (x)
 		 + (unsigned) CONST_DOUBLE_HIGH (x));
+      else
+	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       return hash ? hash : (unsigned int) CONST_DOUBLE;
 
     case CONST_FIXED:
diff --git a/gcc/defaults.h b/gcc/defaults.h
index 4f43f6f0..0801073 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -1404,6 +1404,14 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define SWITCHABLE_TARGET 0
 #endif
 
+/* If the target supports integers that are wider than two
+   HOST_WIDE_INTs on the host compiler, then the target should define
+   TARGET_SUPPORTS_WIDE_INT and make the appropriate fixups.
+   Otherwise the compiler really is not robust.  */
+#ifndef TARGET_SUPPORTS_WIDE_INT
+#define TARGET_SUPPORTS_WIDE_INT 0
+#endif
+
 #endif /* GCC_INSN_FLAGS_H  */
 
 #endif  /* ! GCC_DEFAULTS_H */
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 8829b0e..2254e2f 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -1525,17 +1525,22 @@ Similarly, there is only one object for the integer whose value is
 
 @findex const_double
 @item (const_double:@var{m} @var{i0} @var{i1} @dots{})
-Represents either a floating-point constant of mode @var{m} or an
-integer constant too large to fit into @code{HOST_BITS_PER_WIDE_INT}
-bits but small enough to fit within twice that number of bits (GCC
-does not provide a mechanism to represent even larger constants).  In
-the latter case, @var{m} will be @code{VOIDmode}.  For integral values
-constants for modes with more bits than twice the number in
-@code{HOST_WIDE_INT} the implied high order bits of that constant are
-copies of the top bit of @code{CONST_DOUBLE_HIGH}.  Note however that
-integral values are neither inherently signed nor inherently unsigned;
-where necessary, signedness is determined by the rtl operation
-instead.
+This represents either a floating-point constant of mode @var{m} or
+(on ports older ports that do not define
+@code{TARGET_SUPPORTS_WIDE_INT}) an integer constant too large to fit
+into @code{HOST_BITS_PER_WIDE_INT} bits but small enough to fit within
+twice that number of bits (GCC does not provide a mechanism to
+represent even larger constants).  In the latter case, @var{m} will be
+@code{VOIDmode}.  For integral values constants for modes with more
+bits than twice the number in @code{HOST_WIDE_INT} the implied high
+order bits of that constant are copies of the top bit of
+@code{CONST_DOUBLE_HIGH}.  Note however that integral values are
+neither inherently signed nor inherently unsigned; where necessary,
+signedness is determined by the rtl operation instead.
+
+On more modern ports, @code{CONST_DOUBLE} only represents floating
+point values.  New ports define to @code{TARGET_SUPPORTS_WIDE_INT} to
+make this designation.
 
 @findex CONST_DOUBLE_LOW
 If @var{m} is @code{VOIDmode}, the bits of the value are stored in
@@ -1550,6 +1555,37 @@ machine's or host machine's floating point format.  To convert them to
 the precise bit pattern used by the target machine, use the macro
 @code{REAL_VALUE_TO_TARGET_DOUBLE} and friends (@pxref{Data Output}).
 
+@findex CONST_WIDE_INT
+@item (const_wide_int:@var{m} @var{nunits} @var{elt0} @dots{})
+This contains an array of @code{HOST_WIDE_INTS} that is large enough
+to hold any constant that can be represented on the target.  This form
+of rtl is only used on targets that define
+@code{TARGET_SUPPORTS_WIDE_INT} to be non zero and then
+@code{CONST_DOUBLES} are only used to hold floating point values.  If
+the target leaves @code{TARGET_SUPPORTS_WIDE_INT} defined as 0,
+@code{CONST_WIDE_INT}s are not used and @code{CONST_DOUBLE}s are as
+they were before.
+
+The values are stored in a compressed format.   The higher order
+0s or -1s are not represented if they are just the logical sign
+extension of the number that is represented.   
+
+@findex CONST_WIDE_INT_VEC
+@item CONST_WIDE_INT_VEC (@var{code})
+Returns the entire array of @code{HOST_WIDE_INT}s that are used to
+store the value.   This macro should be rarely used.
+
+@findex CONST_WIDE_INT_NUNITS
+@item CONST_WIDE_INT_NUNITS (@var{code})
+The number of @code{HOST_WIDE_INT}s used to represent the number.
+Note that this generally be smaller than the number of
+@code{HOST_WIDE_INT}s implied by the mode size.
+
+@findex CONST_WIDE_INT_ELT
+@item CONST_WIDE_INT_NUNITS (@var{code},@var{i})
+Returns the @code{i}th element of the array.   Element 0 is contains
+the low order bits of the constant.
+
 @findex const_fixed
 @item (const_fixed:@var{m} @dots{})
 Represents a fixed-point constant of mode @var{m}.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index c88a89f..116864b 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11352,3 +11352,50 @@ It returns true if the target supports GNU indirect functions.
 The support includes the assembler, linker and dynamic linker.
 The default value of this hook is based on target's libc.
 @end deftypefn
+
+@defmac TARGET_SUPPORTS_WIDE_INT
+
+On older ports, large integers are stored in @code{CONST_DOUBLE} rtl
+objects.  Newer ports define @code{TARGET_SUPPORTS_WIDE_INT} to be non
+zero to indicate that large integers are stored in
+@code{CONST_WIDE_INT} rtl objects.  The @code{CONST_WIDE_INT} allows
+very large integer constants to be represented.  @code{CONST_DOUBLE}
+are limited to twice the size of host's @code{HOST_WIDE_INT}
+representation.
+
+Converting a port mostly requires looking for the places where
+@code{CONST_DOUBLES} are used with @code{VOIDmode} and replacing that
+code with code that accesses @code{CONST_WIDE_INT}s.  @samp{"grep -i
+const_double"} at the port level gets you to 95% of the changes that
+need to be made.  There are a few places that require a deeper look.
+
+@itemize @bullet
+@item
+There is no equivalent to @code{hval} and @code{lval} for
+@code{CONST_WIDE_INT}s.  This would be difficult to express in the md
+language since there are a variable number of elements.
+
+Most ports only check that @code{hval} is either 0 or -1 to see if the
+value is small.  As mentioned above, this will no longer be necessary
+since small constants are always @code{CONST_INT}.  Of course there
+are still a few exceptions, the alpha's constraint used by the zap
+instruction certainly requires careful examination by C code.
+However, all the current code does is pass the hval and lval to C
+code, so evolving the c code to look at the @code{CONST_WIDE_INT} is
+not really a large change.
+
+@item
+Because there is no standard template that ports use to materialize
+constants, there is likely to be some futzing that is unique to each
+port in this code.
+
+@item
+The rtx costs may have to be adjusted to properly account for larger
+constants that are represented as @code{CONST_WIDE_INT}.
+@end itemize
+
+All and all it does not takes long to convert ports that the
+maintainer is familiar with.
+
+@end defmac
+
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index d70ce4c..f59ffde 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -11182,3 +11182,50 @@ memory model bits are allowed.
 @hook TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
 
 @hook TARGET_HAS_IFUNC_P
+
+@defmac TARGET_SUPPORTS_WIDE_INT
+
+On older ports, large integers are stored in @code{CONST_DOUBLE} rtl
+objects.  Newer ports define @code{TARGET_SUPPORTS_WIDE_INT} to be non
+zero to indicate that large integers are stored in
+@code{CONST_WIDE_INT} rtl objects.  The @code{CONST_WIDE_INT} allows
+very large integer constants to be represented.  @code{CONST_DOUBLE}
+are limited to twice the size of host's @code{HOST_WIDE_INT}
+representation.
+
+Converting a port mostly requires looking for the places where
+@code{CONST_DOUBLES} are used with @code{VOIDmode} and replacing that
+code with code that accesses @code{CONST_WIDE_INT}s.  @samp{"grep -i
+const_double"} at the port level gets you to 95% of the changes that
+need to be made.  There are a few places that require a deeper look.
+
+@itemize @bullet
+@item
+There is no equivalent to @code{hval} and @code{lval} for
+@code{CONST_WIDE_INT}s.  This would be difficult to express in the md
+language since there are a variable number of elements.
+
+Most ports only check that @code{hval} is either 0 or -1 to see if the
+value is small.  As mentioned above, this will no longer be necessary
+since small constants are always @code{CONST_INT}.  Of course there
+are still a few exceptions, the alpha's constraint used by the zap
+instruction certainly requires careful examination by C code.
+However, all the current code does is pass the hval and lval to C
+code, so evolving the c code to look at the @code{CONST_WIDE_INT} is
+not really a large change.
+
+@item
+Because there is no standard template that ports use to materialize
+constants, there is likely to be some futzing that is unique to each
+port in this code.
+
+@item
+The rtx costs may have to be adjusted to properly account for larger
+constants that are represented as @code{CONST_WIDE_INT}.
+@end itemize
+
+All and all it does not takes long to convert ports that the
+maintainer is familiar with.
+
+@end defmac
+
diff --git a/gcc/dojump.c b/gcc/dojump.c
index 3f04eac..ecbec40 100644
--- a/gcc/dojump.c
+++ b/gcc/dojump.c
@@ -142,6 +142,7 @@ static bool
 prefer_and_bit_test (enum machine_mode mode, int bitnum)
 {
   bool speed_p;
+  wide_int mask = wide_int::set_bit_in_zero (bitnum, mode);
 
   if (and_test == 0)
     {
@@ -162,8 +163,7 @@ prefer_and_bit_test (enum machine_mode mode, int bitnum)
     }
 
   /* Fill in the integers.  */
-  XEXP (and_test, 1)
-    = immed_double_int_const (double_int_zero.set_bit (bitnum), mode);
+  XEXP (and_test, 1) = immed_wide_int_const (mask, mode);
   XEXP (XEXP (shift_test, 0), 1) = GEN_INT (bitnum);
 
   speed_p = optimize_insn_for_speed_p ();
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 2475ade..6fd3eae 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -323,6 +323,17 @@ 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)
 {
@@ -1354,6 +1365,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;
@@ -1610,6 +1624,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 ();
 	  }
@@ -1787,6 +1805,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);
@@ -1996,6 +2028,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 ();
 	  }
@@ -3095,7 +3142,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 *);
 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,
@@ -3720,6 +3767,20 @@ AT_unsigned (dw_attr_ref a)
 /* Add an unsigned double integer attribute value to a DIE.  */
 
 static inline void
+add_AT_wide (dw_die_ref die, enum dwarf_attribute attr_kind,
+	     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 = w;
+  add_dwarf_attr (die, &attr);
+}
+
+/* Add an unsigned double integer attribute value to a DIE.  */
+
+static inline void
 add_AT_double (dw_die_ref die, enum dwarf_attribute attr_kind,
 	       HOST_WIDE_INT high, unsigned HOST_WIDE_INT low)
 {
@@ -5273,6 +5334,19 @@ 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;
@@ -5444,6 +5518,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 (at->dw_attr_val.v.val_vec);
       break;
@@ -5714,6 +5791,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 (sizeof (at->dw_attr_val.v.val_vec));
@@ -6178,6 +6261,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)
@@ -7640,6 +7725,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)
@@ -7978,6 +8070,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))
@@ -8417,6 +8523,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;
@@ -11550,9 +11682,8 @@ 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 
+      (wide_int::set_bit_in_zero (GET_MODE_PRECISION (mode) - 1, 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
@@ -12493,7 +12624,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
@@ -12505,13 +12645,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
+	    = wide_int::from_rtx (rtl, mode);
 	}
       break;
 
@@ -12982,7 +13135,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
@@ -12994,12 +13155,26 @@ 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))
+	{
+	  gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
+
+	  /* Note that a CONST_DOUBLE rtx could represent either an integer
+	     or a floating-point constant.  A CONST_DOUBLE is used whenever
+	     the constant requires more than one word in order to be
+	     adequately represented.  We output CONST_DOUBLEs as blocks.  */
+	  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
+	    = wide_int::from_rtx (rtl, mode);
 	}
       break;
 
@@ -13015,6 +13190,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))
@@ -13023,15 +13199,8 @@ 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);
-		    }
+		  wide_int val = wide_int::from_rtx (elt, imode);
+		  insert_wide_int (val, p);
 		}
 	      break;
 
@@ -14656,22 +14825,27 @@ 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)
 {
-  unsigned char *p0 = dest;
-  unsigned char *p1 = dest + sizeof (HOST_WIDE_INT);
+  int i;
 
   if (WORDS_BIG_ENDIAN)
-    {
-      p0 = p1;
-      p1 = dest;
-    }
-
-  insert_int ((HOST_WIDE_INT) val.low, sizeof (HOST_WIDE_INT), p0);
-  insert_int ((HOST_WIDE_INT) val.high, sizeof (HOST_WIDE_INT), p1);
+    for (i = (int)get_full_len (val) - 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 < (int)get_full_len (val); 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.  */
@@ -14716,6 +14890,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,
+		   wide_int::from_rtx (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
@@ -14724,7 +14903,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);
@@ -14732,9 +14914,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;
 
@@ -14747,6 +14926,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))
 	  {
@@ -14754,15 +14934,8 @@ 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);
-		  }
+		wide_int val = wide_int::from_rtx (elt, imode);
+		insert_wide_int (val, p);
 	      }
 	    break;
 
@@ -23091,6 +23264,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;
@@ -23180,6 +23356,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 ();
 	  }
@@ -23328,6 +23507,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:
@@ -23371,6 +23552,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 ();
 	}
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index ad03a34..531a7c1 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_DWARF2OUT_H 1
 
 #include "dwarf2.h"	/* ??? Remove this once only used by dwarf2foo.c.  */
+#include "wide-int.h"
 
 typedef struct die_struct *dw_die_ref;
 typedef const struct die_struct *const_dw_die_ref;
@@ -139,6 +140,7 @@ enum dw_val_class
   dw_val_class_const,
   dw_val_class_unsigned_const,
   dw_val_class_const_double,
+  dw_val_class_wide_int,
   dw_val_class_vec,
   dw_val_class_flag,
   dw_val_class_die_ref,
@@ -180,6 +182,7 @@ typedef struct GTY(()) dw_val_struct {
       HOST_WIDE_INT GTY ((default)) val_int;
       unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
       double_int GTY ((tag ("dw_val_class_const_double"))) val_double;
+      wide_int GTY ((tag ("dw_val_class_wide_int"))) val_wide;
       dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
       struct dw_val_die_union
 	{
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 5a24a791..dfb0abc 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -124,6 +124,9 @@ rtx cc0_rtx;
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
      htab_t const_int_htab;
 
+static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
+     htab_t const_wide_int_htab;
+
 /* A hash table storing memory attribute structures.  */
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct mem_attrs)))
      htab_t mem_attrs_htab;
@@ -149,6 +152,11 @@ static void set_used_decls (tree);
 static void mark_label_nuses (rtx);
 static hashval_t const_int_htab_hash (const void *);
 static int const_int_htab_eq (const void *, const void *);
+#if TARGET_SUPPORTS_WIDE_INT
+static hashval_t const_wide_int_htab_hash (const void *);
+static int const_wide_int_htab_eq (const void *, const void *);
+static rtx lookup_const_wide_int (rtx);
+#endif
 static hashval_t const_double_htab_hash (const void *);
 static int const_double_htab_eq (const void *, const void *);
 static rtx lookup_const_double (rtx);
@@ -185,6 +193,43 @@ const_int_htab_eq (const void *x, const void *y)
   return (INTVAL ((const_rtx) x) == *((const HOST_WIDE_INT *) y));
 }
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns a hash code for X (which is a really a CONST_WIDE_INT).  */
+
+static hashval_t
+const_wide_int_htab_hash (const void *x)
+{
+  int i;
+  HOST_WIDE_INT hash = 0;
+  const_rtx xr = (const_rtx) x;
+
+  for (i = 0; i < CONST_WIDE_INT_NUNITS (xr); i++)
+    hash += CONST_WIDE_INT_ELT (xr, i);
+
+  return (hashval_t) hash;
+}
+
+/* Returns nonzero if the value represented by X (which is really a
+   CONST_WIDE_INT) is the same as that given by Y (which is really a
+   CONST_WIDE_INT).  */
+
+static int
+const_wide_int_htab_eq (const void *x, const void *y)
+{
+  int i;
+  const_rtx xr = (const_rtx)x;
+  const_rtx yr = (const_rtx)y;
+  if (CONST_WIDE_INT_NUNITS (xr) != CONST_WIDE_INT_NUNITS (yr))
+    return 0;
+
+  for (i = 0; i < CONST_WIDE_INT_NUNITS (xr); i++)
+    if (CONST_WIDE_INT_ELT (xr, i) != CONST_WIDE_INT_ELT (yr, i))
+      return 0;
+  
+  return 1;
+}
+#endif
+
 /* Returns a hash code for X (which is really a CONST_DOUBLE).  */
 static hashval_t
 const_double_htab_hash (const void *x)
@@ -192,7 +237,7 @@ const_double_htab_hash (const void *x)
   const_rtx const value = (const_rtx) x;
   hashval_t h;
 
-  if (GET_MODE (value) == VOIDmode)
+  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (value) == VOIDmode)
     h = CONST_DOUBLE_LOW (value) ^ CONST_DOUBLE_HIGH (value);
   else
     {
@@ -212,7 +257,7 @@ const_double_htab_eq (const void *x, const void *y)
 
   if (GET_MODE (a) != GET_MODE (b))
     return 0;
-  if (GET_MODE (a) == VOIDmode)
+  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (a) == VOIDmode)
     return (CONST_DOUBLE_LOW (a) == CONST_DOUBLE_LOW (b)
 	    && CONST_DOUBLE_HIGH (a) == CONST_DOUBLE_HIGH (b));
   else
@@ -478,6 +523,7 @@ const_fixed_from_fixed_value (FIXED_VALUE_TYPE value, enum machine_mode mode)
   return lookup_const_fixed (fixed);
 }
 
+#if TARGET_SUPPORTS_WIDE_INT == 0
 /* Constructs double_int from rtx CST.  */
 
 double_int
@@ -497,17 +543,60 @@ rtx_to_double_int (const_rtx cst)
   
   return r;
 }
+#endif
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Determine whether WIDE_INT, already exists in the hash table.  If
+   so, return its counterpart; otherwise add it to the hash table and
+   return it.  */
+
+static rtx
+lookup_const_wide_int (rtx wint)
+{
+  void **slot = htab_find_slot (const_wide_int_htab, wint, INSERT);
+  if (*slot == 0)
+    *slot = wint;
 
-/* Return a CONST_DOUBLE or CONST_INT for a value specified as
-   a double_int.  */
+  return (rtx) *slot;
+}
+#endif
 
+/* V contains a wide_int.  A CONST_INT or CONST_WIDE_INT (if
+   TARGET_SUPPORTS_WIDE_INT is defined) or CONST_DOUBLE if
+   TARGET_SUPPORTS_WIDE_INT is not defined is produced based on the
+   number of HOST_WIDE_INTs that are necessary to represent the value
+   in compact form.  */
 rtx
-immed_double_int_const (double_int i, enum machine_mode mode)
+immed_wide_int_const (const wide_int &v, enum machine_mode mode)
 {
-  return immed_double_const (i.low, i.high, mode);
+  unsigned int len = v.get_len ();
+
+  if (len < 2)
+    return gen_int_mode (v.elt (0), mode);
+
+  gcc_assert (GET_MODE_PRECISION (mode) == v.get_precision ());
+
+#if TARGET_SUPPORTS_WIDE_INT
+  {
+    rtx value = const_wide_int_alloc (len);
+    unsigned int i;
+
+    /* It is so tempting to just put the mode in here.  Must control
+       myself ... */
+    PUT_MODE (value, VOIDmode);
+    HWI_PUT_NUM_ELEM (CONST_WIDE_INT_VEC (value), len);
+
+    for (i = 0; i < len; i++)
+      CONST_WIDE_INT_ELT (value, i) = v.elt (i);
+
+    return lookup_const_wide_int (value);
+  }
+#else
+  return immed_double_const (v.elt (0), v.elt (1), mode);
+#endif
 }
 
+#if TARGET_SUPPORTS_WIDE_INT == 0
 /* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair
    of ints: I0 is the low-order word and I1 is the high-order word.
    For values that are larger than HOST_BITS_PER_DOUBLE_INT, the
@@ -559,6 +648,7 @@ immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode)
 
   return lookup_const_double (value);
 }
+#endif
 
 rtx
 gen_rtx_REG (enum machine_mode mode, unsigned int regno)
@@ -5616,11 +5706,15 @@ init_emit_once (void)
   enum machine_mode mode;
   enum machine_mode double_mode;
 
-  /* Initialize the CONST_INT, CONST_DOUBLE, CONST_FIXED, and memory attribute
-     hash tables.  */
+  /* Initialize the CONST_INT, CONST_WIDE_INT, CONST_DOUBLE,
+     CONST_FIXED, and memory attribute hash tables.  */
   const_int_htab = htab_create_ggc (37, const_int_htab_hash,
 				    const_int_htab_eq, NULL);
 
+#if TARGET_SUPPORTS_WIDE_INT
+  const_wide_int_htab = htab_create_ggc (37, const_wide_int_htab_hash,
+					 const_wide_int_htab_eq, NULL);
+#endif
   const_double_htab = htab_create_ggc (37, const_double_htab_hash,
 				       const_double_htab_eq, NULL);
 
diff --git a/gcc/explow.c b/gcc/explow.c
index 08a6653..c154472 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -95,38 +95,9 @@ plus_constant (enum machine_mode mode, rtx x, HOST_WIDE_INT c)
 
   switch (code)
     {
-    case CONST_INT:
-      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
-	{
-	  double_int di_x = double_int::from_shwi (INTVAL (x));
-	  double_int di_c = double_int::from_shwi (c);
-
-	  bool overflow;
-	  double_int v = di_x.add_with_sign (di_c, false, &overflow);
-	  if (overflow)
-	    gcc_unreachable ();
-
-	  return immed_double_int_const (v, VOIDmode);
-	}
-
-      return GEN_INT (INTVAL (x) + c);
-
-    case CONST_DOUBLE:
-      {
-	double_int di_x = double_int::from_pair (CONST_DOUBLE_HIGH (x),
-						 CONST_DOUBLE_LOW (x));
-	double_int di_c = double_int::from_shwi (c);
-
-	bool overflow;
-	double_int v = di_x.add_with_sign (di_c, false, &overflow);
-	if (overflow)
-	  /* Sorry, we have no way to represent overflows this wide.
-	     To fix, add constant support wider than CONST_DOUBLE.  */
-	  gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT);
-
-	return immed_double_int_const (v, VOIDmode);
-      }
-
+    CASE_CONST_SCALAR_INT:
+      return immed_wide_int_const (wide_int::from_rtx (x, mode) 
+				   + wide_int::from_shwi (c, mode), mode);
     case MEM:
       /* If this is a reference to the constant pool, try replacing it with
 	 a reference to a new constant.  If the resulting address isn't
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 3c3a179..ae726c2 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -55,7 +55,6 @@ static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
 static rtx extract_fixed_bit_field (enum machine_mode, rtx,
 				    unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT, rtx, int, bool);
-static rtx mask_rtx (enum machine_mode, int, int, int);
 static rtx lshift_value (enum machine_mode, rtx, int, int);
 static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT, int);
@@ -63,6 +62,18 @@ static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
 static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 
+/* Return a constant integer mask value of mode MODE with BITSIZE ones
+   followed by BITPOS zeros, or the complement of that if COMPLEMENT.
+   The mask is truncated if necessary to the width of mode MODE.  The
+   mask is zero-extended if BITSIZE+BITPOS is too small for MODE.  */
+
+static inline rtx 
+mask_rtx (enum machine_mode mode, int bitpos, int bitsize, bool complement)
+{
+  return immed_wide_int_const 
+    (wide_int::shifted_mask (bitpos, bitsize, complement, mode), mode);
+}
+
 /* Test whether a value is zero of a power of two.  */
 #define EXACT_POWER_OF_2_OR_ZERO_P(x) \
   (((x) & ((x) - (unsigned HOST_WIDE_INT) 1)) == 0)
@@ -1832,39 +1843,15 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
   return expand_shift (RSHIFT_EXPR, mode, op0,
 		       GET_MODE_BITSIZE (mode) - bitsize, target, 0);
 }
-\f
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) mask value
-   of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
-   complement of that if COMPLEMENT.  The mask is truncated if
-   necessary to the width of mode MODE.  The mask is zero-extended if
-   BITSIZE+BITPOS is too small for MODE.  */
-
-static rtx
-mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
-{
-  double_int mask;
-
-  mask = double_int::mask (bitsize);
-  mask = mask.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
-  if (complement)
-    mask = ~mask;
-
-  return immed_double_int_const (mask, mode);
-}
-
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
-   VALUE truncated to BITSIZE bits and then shifted left BITPOS bits.  */
+/* Return a constant integer rtx with the value VALUE truncated to
+   BITSIZE bits and then shifted left BITPOS bits.  */
 
 static rtx
 lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
 {
-  double_int val;
-  
-  val = double_int::from_uhwi (INTVAL (value)).zext (bitsize);
-  val = val.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
-  return immed_double_int_const (val, mode);
+  return 
+    immed_wide_int_const (wide_int::from_rtx (value, mode)
+			  .zext (bitsize).lshift (bitpos), mode);
 }
 \f
 /* Extract a bit field that is split across two words
@@ -3069,37 +3056,41 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 	 only if the constant value exactly fits in an `unsigned int' without
 	 any truncation.  This means that multiplying by negative values does
 	 not work; results are off by 2^32 on a 32 bit machine.  */
-
       if (CONST_INT_P (scalar_op1))
 	{
 	  coeff = INTVAL (scalar_op1);
 	  is_neg = coeff < 0;
 	}
+#if TARGET_SUPPORTS_WIDE_INT
+      else if (CONST_WIDE_INT_P (scalar_op1))
+#else
       else if (CONST_DOUBLE_AS_INT_P (scalar_op1))
+#endif
 	{
-	  /* If we are multiplying in DImode, it may still be a win
-	     to try to work with shifts and adds.  */
-	  if (CONST_DOUBLE_HIGH (scalar_op1) == 0
-	      && (CONST_DOUBLE_LOW (scalar_op1) > 0
-		  || (CONST_DOUBLE_LOW (scalar_op1) < 0
-		      && EXACT_POWER_OF_2_OR_ZERO_P
-			   (CONST_DOUBLE_LOW (scalar_op1)))))
+	  int p = GET_MODE_PRECISION (mode);
+	  wide_int val = wide_int::from_rtx (scalar_op1, mode);
+	  int shift = val.exact_log2 ().to_shwi (); 
+	  /* Perfect power of 2.  */
+	  is_neg = false;
+	  if (shift > 0)
 	    {
-	      coeff = CONST_DOUBLE_LOW (scalar_op1);
-	      is_neg = false;
+	      /* Do the shift count trucation against the bitsize, not
+		 the precision.  See the comment above
+		 wide-int.c:trunc_shift for details.  */
+	      if (SHIFT_COUNT_TRUNCATED)
+		shift &= GET_MODE_BITSIZE (mode) - 1;
+	      /* We could consider adding just a move of 0 to target
+		 if the shift >= p  */
+	      if (shift < p)
+		return expand_shift (LSHIFT_EXPR, mode, op0, 
+				     shift, target, unsignedp);
+	      /* Any positive number that fits in a word.  */
+	      coeff = CONST_WIDE_INT_ELT (scalar_op1, 0);
 	    }
-	  else if (CONST_DOUBLE_LOW (scalar_op1) == 0)
+	  else if (val.sign_mask () == 0)
 	    {
-	      coeff = CONST_DOUBLE_HIGH (scalar_op1);
-	      if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
-		{
-		  int shift = floor_log2 (coeff) + HOST_BITS_PER_WIDE_INT;
-		  if (shift < HOST_BITS_PER_DOUBLE_INT - 1
-		      || mode_bitsize <= HOST_BITS_PER_DOUBLE_INT)
-		    return expand_shift (LSHIFT_EXPR, mode, op0,
-					 shift, target, unsignedp);
-		}
-	      goto skip_synth;
+	      /* Any positive number that fits in a word.  */
+	      coeff = CONST_WIDE_INT_ELT (scalar_op1, 0);
 	    }
 	  else
 	    goto skip_synth;
@@ -3601,9 +3592,10 @@ expmed_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
 static rtx
 expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 {
-  unsigned HOST_WIDE_INT masklow, maskhigh;
   rtx result, temp, shift, label;
   int logd;
+  wide_int mask;
+  int prec = GET_MODE_PRECISION (mode);
 
   logd = floor_log2 (d);
   result = gen_reg_rtx (mode);
@@ -3616,8 +3608,8 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 				      mode, 0, -1);
       if (signmask)
 	{
+	  HOST_WIDE_INT masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
 	  signmask = force_reg (mode, signmask);
-	  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
 	  shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
 
 	  /* Use the rtx_cost of a LSHIFTRT instruction to determine
@@ -3662,19 +3654,11 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
      modulus.  By including the signbit in the operation, many targets
      can avoid an explicit compare operation in the following comparison
      against zero.  */
-
-  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
-  if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
-    {
-      masklow |= (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1);
-      maskhigh = -1;
-    }
-  else
-    maskhigh = (HOST_WIDE_INT) -1
-		 << (GET_MODE_BITSIZE (mode) - HOST_BITS_PER_WIDE_INT - 1);
+  mask = wide_int::mask (logd, false, mode);
+  mask = mask.set_bit (prec - 1);
 
   temp = expand_binop (mode, and_optab, op0,
-		       immed_double_const (masklow, maskhigh, mode),
+		       immed_wide_int_const (mask, mode),
 		       result, 1, OPTAB_LIB_WIDEN);
   if (temp != result)
     emit_move_insn (result, temp);
@@ -3684,10 +3668,10 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 
   temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
 		       0, OPTAB_LIB_WIDEN);
-  masklow = (HOST_WIDE_INT) -1 << logd;
-  maskhigh = -1;
+
+  mask = wide_int::mask (logd, true, mode); 
   temp = expand_binop (mode, ior_optab, temp,
-		       immed_double_const (masklow, maskhigh, mode),
+		       immed_wide_int_const (mask, mode),
 		       result, 1, OPTAB_LIB_WIDEN);
   temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
 		       0, OPTAB_LIB_WIDEN);
@@ -4940,8 +4924,12 @@ make_tree (tree type, rtx x)
 	return t;
       }
 
+    case CONST_WIDE_INT:
+      t = wide_int_to_tree (type, wide_int::from_rtx (x, TYPE_MODE (type)));
+      return t;
+
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	t = build_int_cst_wide (type,
 				CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
       else
diff --git a/gcc/expr.c b/gcc/expr.c
index e3fb0b6..6c8b1b5 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -710,23 +710,23 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
   if (mode == oldmode)
     return x;
 
-  /* There is one case that we must handle specially: If we are converting
-     a CONST_INT into a mode whose size is twice HOST_BITS_PER_WIDE_INT and
-     we are to interpret the constant as unsigned, gen_lowpart will do
-     the wrong if the constant appears negative.  What we want to do is
-     make the high-order word of the constant zero, not all ones.  */
+  /* There is one case that we must handle specially: If we are
+     converting a CONST_INT into a mode whose size is larger than
+     HOST_BITS_PER_WIDE_INT and we are to interpret the constant as
+     unsigned, gen_lowpart will do the wrong if the constant appears
+     negative.  What we want to do is make the high-order word of the
+     constant zero, not all ones.  */
 
   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
-      && GET_MODE_BITSIZE (mode) == HOST_BITS_PER_DOUBLE_INT
+      && GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT
       && CONST_INT_P (x) && INTVAL (x) < 0)
     {
-      double_int val = double_int::from_uhwi (INTVAL (x));
-
+      HOST_WIDE_INT val = INTVAL (x);
       /* We need to zero extend VAL.  */
       if (oldmode != VOIDmode)
-	val = val.zext (GET_MODE_BITSIZE (oldmode));
+	val &= GET_MODE_PRECISION (oldmode) - 1;
 
-      return immed_double_int_const (val, mode);
+      return immed_wide_int_const (wide_int::from_uhwi (val, mode), mode);
     }
 
   /* We can do this with a gen_lowpart if both desired and current modes
@@ -738,7 +738,11 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
        && GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT)
       || (GET_MODE_CLASS (mode) == MODE_INT
 	  && GET_MODE_CLASS (oldmode) == MODE_INT
-	  && (CONST_DOUBLE_AS_INT_P (x) 
+#if TARGET_SUPPORTS_WIDE_INT
+	  && (CONST_WIDE_INT_P (x)
+#else
+ 	  && (CONST_DOUBLE_AS_INT_P (x)
+#endif
 	      || (GET_MODE_PRECISION (mode) <= GET_MODE_PRECISION (oldmode)
 		  && ((MEM_P (x) && ! MEM_VOLATILE_P (x)
 		       && direct_load[(int) mode])
@@ -1743,6 +1747,7 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
 	    {
 	      rtx first, second;
 
+	      /* TODO: const_wide_int can have sizes other than this...  */
 	      gcc_assert (2 * len == ssize);
 	      split_double (src, &first, &second);
 	      if (i)
@@ -5239,10 +5244,10 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 			       &alt_rtl);
     }
 
-  /* If TEMP is a VOIDmode constant and the mode of the type of EXP is not
-     the same as that of TARGET, adjust the constant.  This is needed, for
-     example, in case it is a CONST_DOUBLE and we want only a word-sized
-     value.  */
+  /* If TEMP is a VOIDmode constant and the mode of the type of EXP is
+     not the same as that of TARGET, adjust the constant.  This is
+     needed, for example, in case it is a CONST_DOUBLE or
+     CONST_WIDE_INT and we want only a word-sized value.  */
   if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode
       && TREE_CODE (exp) != ERROR_MARK
       && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
@@ -7741,11 +7746,12 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
 
   /* All elts simple constants => refer to a constant in memory.  But
      if this is a non-BLKmode mode, let it store a field at a time
-     since that should make a CONST_INT or CONST_DOUBLE when we
-     fold.  Likewise, if we have a target we can use, it is best to
-     store directly into the target unless the type is large enough
-     that memcpy will be used.  If we are making an initializer and
-     all operands are constant, put it in memory as well.
+     since that should make a CONST_INT, CONST_WIDE_INT or
+     CONST_DOUBLE when we fold.  Likewise, if we have a target we can
+     use, it is best to store directly into the target unless the type
+     is large enough that memcpy will be used.  If we are making an
+     initializer and all operands are constant, put it in memory as
+     well.
 
      FIXME: Avoid trying to fill vector constructors piece-meal.
      Output them with output_constant_def below unless we're sure
@@ -8215,17 +8221,18 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 	      && TREE_CONSTANT (treeop1))
 	    {
 	      rtx constant_part;
+	      HOST_WIDE_INT wc;
+	      enum machine_mode wmode = TYPE_MODE (TREE_TYPE (treeop1));
 
 	      op1 = expand_expr (treeop1, subtarget, VOIDmode,
 				 EXPAND_SUM);
-	      /* Use immed_double_const to ensure that the constant is
+	      /* Use wide_int::from_shwi to ensure that the constant is
 		 truncated according to the mode of OP1, then sign extended
 		 to a HOST_WIDE_INT.  Using the constant directly can result
 		 in non-canonical RTL in a 64x32 cross compile.  */
-	      constant_part
-		= immed_double_const (TREE_INT_CST_LOW (treeop0),
-				      (HOST_WIDE_INT) 0,
-				      TYPE_MODE (TREE_TYPE (treeop1)));
+	      wc = TREE_INT_CST_LOW (treeop0);
+	      constant_part 
+		= immed_wide_int_const (wide_int::from_shwi (wc, wmode), wmode);
 	      op1 = plus_constant (mode, op1, INTVAL (constant_part));
 	      if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
 		op1 = force_operand (op1, target);
@@ -8237,7 +8244,8 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 		   && TREE_CONSTANT (treeop0))
 	    {
 	      rtx constant_part;
-
+	      HOST_WIDE_INT wc;
+	      enum machine_mode wmode = TYPE_MODE (TREE_TYPE (treeop0));
 	      op0 = expand_expr (treeop0, subtarget, VOIDmode,
 				 (modifier == EXPAND_INITIALIZER
 				 ? EXPAND_INITIALIZER : EXPAND_SUM));
@@ -8251,14 +8259,13 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 		    return simplify_gen_binary (PLUS, mode, op0, op1);
 		  goto binop2;
 		}
-	      /* Use immed_double_const to ensure that the constant is
+	      /* Use wide_int::from_shwi to ensure that the constant is
 		 truncated according to the mode of OP1, then sign extended
 		 to a HOST_WIDE_INT.  Using the constant directly can result
 		 in non-canonical RTL in a 64x32 cross compile.  */
-	      constant_part
-		= immed_double_const (TREE_INT_CST_LOW (treeop1),
-				      (HOST_WIDE_INT) 0,
-				      TYPE_MODE (TREE_TYPE (treeop0)));
+	      wc = TREE_INT_CST_LOW (treeop1);
+	      constant_part 
+		= immed_wide_int_const (wide_int::from_shwi (wc, wmode), wmode);
 	      op0 = plus_constant (mode, op0, INTVAL (constant_part));
 	      if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
 		op0 = force_operand (op0, target);
@@ -8760,10 +8767,13 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 	 for unsigned bitfield expand this as XOR with a proper constant
 	 instead.  */
       if (reduce_bit_field && TYPE_UNSIGNED (type))
-	temp = expand_binop (mode, xor_optab, op0,
-			     immed_double_int_const
-			       (double_int::mask (TYPE_PRECISION (type)), mode),
-			     target, 1, OPTAB_LIB_WIDEN);
+	{
+	  wide_int mask = wide_int::mask (TYPE_PRECISION (type), false, mode);
+
+	  temp = expand_binop (mode, xor_optab, op0,
+			       immed_wide_int_const (mask, mode),
+			       target, 1, OPTAB_LIB_WIDEN);
+	}
       else
 	temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
       gcc_assert (temp);
@@ -9396,9 +9406,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return decl_rtl;
 
     case INTEGER_CST:
-      temp = immed_double_const (TREE_INT_CST_LOW (exp),
-				 TREE_INT_CST_HIGH (exp), mode);
-
+      temp = immed_wide_int_const (wide_int::from_tree (exp), 
+				   TYPE_MODE (TREE_TYPE (exp)));
       return temp;
 
     case VECTOR_CST:
@@ -9630,8 +9639,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 	op0 = memory_address_addr_space (address_mode, op0, as);
 	if (!integer_zerop (TREE_OPERAND (exp, 1)))
 	  {
-	    rtx off
-	      = immed_double_int_const (mem_ref_offset (exp), address_mode);
+	    wide_int wi = wide_int::from_double_int
+	      (mem_ref_offset (exp), address_mode);
+	    rtx off = immed_wide_int_const (wi, address_mode);
 	    op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
 	  }
 	op0 = memory_address_addr_space (mode, op0, as);
@@ -10510,9 +10520,10 @@ reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
     }
   else if (TYPE_UNSIGNED (type))
     {
-      rtx mask = immed_double_int_const (double_int::mask (prec),
-					 GET_MODE (exp));
-      return expand_and (GET_MODE (exp), exp, mask, target);
+      enum machine_mode mode = GET_MODE (exp);
+      rtx mask = immed_wide_int_const 
+	(wide_int::mask (prec, false, mode), mode);
+      return expand_and (mode, exp, mask, target);
     }
   else
     {
@@ -11084,8 +11095,9 @@ const_vector_from_tree (tree exp)
 	RTVEC_ELT (v, i) = CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (elt),
 							 inner);
       else
-	RTVEC_ELT (v, i) = immed_double_int_const (tree_to_double_int (elt),
-						   inner);
+	RTVEC_ELT (v, i) 
+	  = immed_wide_int_const (wide_int::from_tree (elt),
+				  TYPE_MODE (TREE_TYPE (elt)));
     }
 
   return gen_rtx_CONST_VECTOR (mode, v);
diff --git a/gcc/final.c b/gcc/final.c
index f6974f4..053aebc 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -3789,8 +3789,16 @@ output_addr_const (FILE *file, rtx x)
       output_addr_const (file, XEXP (x, 0));
       break;
 
+    case CONST_WIDE_INT:
+      /* This should be ok for a while.  */
+      gcc_assert (CONST_WIDE_INT_NUNITS (x) == 2);
+      fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
+	       (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, 1),
+	       (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, 0));
+      break;
+
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
+      if (CONST_DOUBLE_AS_INT_P (x))
 	{
 	  /* We can use %d if the number is one word and positive.  */
 	  if (CONST_DOUBLE_HIGH (x))
diff --git a/gcc/genemit.c b/gcc/genemit.c
index 692ef52..7b1e471 100644
--- a/gcc/genemit.c
+++ b/gcc/genemit.c
@@ -204,6 +204,7 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used)
 
     case CONST_DOUBLE:
     case CONST_FIXED:
+    case CONST_WIDE_INT:
       /* These shouldn't be written in MD files.  Instead, the appropriate
 	 routines in varasm.c should be called.  */
       gcc_unreachable ();
diff --git a/gcc/gengenrtl.c b/gcc/gengenrtl.c
index 5b5a3ca..1f93dd5 100644
--- a/gcc/gengenrtl.c
+++ b/gcc/gengenrtl.c
@@ -142,6 +142,7 @@ static int
 excluded_rtx (int idx)
 {
   return ((strcmp (defs[idx].enumname, "CONST_DOUBLE") == 0)
+	  || (strcmp (defs[idx].enumname, "CONST_WIDE_INT") == 0)
 	  || (strcmp (defs[idx].enumname, "CONST_FIXED") == 0));
 }
 
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index eede798..ca2ee25 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -5442,6 +5442,7 @@ main (int argc, char **argv)
       POS_HERE (do_scalar_typedef ("REAL_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("FIXED_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("double_int", &pos));
+      POS_HERE (do_scalar_typedef ("wide_int", &pos));
       POS_HERE (do_scalar_typedef ("uint64_t", &pos));
       POS_HERE (do_scalar_typedef ("uint8", &pos));
       POS_HERE (do_scalar_typedef ("uintptr_t", &pos));
diff --git a/gcc/genpreds.c b/gcc/genpreds.c
index 98488e3..29fafbe 100644
--- a/gcc/genpreds.c
+++ b/gcc/genpreds.c
@@ -612,7 +612,7 @@ write_one_predicate_function (struct pred_data *p)
   add_mode_tests (p);
 
   /* A normal predicate can legitimately not look at enum machine_mode
-     if it accepts only CONST_INTs and/or CONST_DOUBLEs.  */
+     if it accepts only CONST_INTs and/or CONST_WIDE_INT and/or CONST_DOUBLEs.  */
   printf ("int\n%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n{\n",
 	  p->name);
   write_predicate_stmts (p->exp);
@@ -809,8 +809,11 @@ add_constraint (const char *name, const char *regclass,
   if (is_const_int || is_const_dbl)
     {
       enum rtx_code appropriate_code
+#if TARGET_SUPPORTS_WIDE_INT
+	= is_const_int ? CONST_INT : CONST_WIDE_INT;
+#else
 	= is_const_int ? CONST_INT : CONST_DOUBLE;
-
+#endif
       /* Consider relaxing this requirement in the future.  */
       if (regclass
 	  || GET_CODE (exp) != AND
@@ -1075,12 +1078,17 @@ write_tm_constrs_h (void)
 	if (needs_ival)
 	  puts ("  if (CONST_INT_P (op))\n"
 		"    ival = INTVAL (op);");
+#if TARGET_SUPPORTS_WIDE_INT
+	if (needs_lval || needs_hval)
+	  error ("you can't use lval or hval");
+#else
 	if (needs_hval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)"
 		"    hval = CONST_DOUBLE_HIGH (op);");
 	if (needs_lval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)"
 		"    lval = CONST_DOUBLE_LOW (op);");
+#endif
 	if (needs_rval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode != VOIDmode)"
 		"    rval = CONST_DOUBLE_REAL_VALUE (op);");
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index 9b9a03e..638e051 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -2775,7 +2775,13 @@ static const struct std_pred_table std_preds[] = {
   {"scratch_operand", false, false, {SCRATCH, REG}},
   {"immediate_operand", false, true, {UNKNOWN}},
   {"const_int_operand", false, false, {CONST_INT}},
+#if TARGET_SUPPORTS_WIDE_INT
+  {"const_wide_int_operand", false, false, {CONST_WIDE_INT}},
+  {"const_scalar_int_operand", false, false, {CONST_INT, CONST_WIDE_INT}},
+  {"const_double_operand", false, false, {CONST_DOUBLE}},
+#else
   {"const_double_operand", false, false, {CONST_INT, CONST_DOUBLE}},
+#endif
   {"nonimmediate_operand", false, false, {SUBREG, REG, MEM}},
   {"nonmemory_operand", false, true, {SUBREG, REG}},
   {"push_operand", false, false, {MEM}},
diff --git a/gcc/optabs.c b/gcc/optabs.c
index a3051ad..3b534b2 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -851,7 +851,8 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
   if (CONSTANT_P (op1) || shift_mask >= BITS_PER_WORD)
     {
       carries = outof_input;
-      tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
+      tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD,
+						       op1_mode), op1_mode);
       tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
 				   0, true, methods);
     }
@@ -866,13 +867,14 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
 			      outof_input, const1_rtx, 0, unsignedp, methods);
       if (shift_mask == BITS_PER_WORD - 1)
 	{
-	  tmp = immed_double_const (-1, -1, op1_mode);
+	  tmp = immed_wide_int_const (wide_int::minus_one (op1_mode), op1_mode);
 	  tmp = simplify_expand_binop (op1_mode, xor_optab, op1, tmp,
 				       0, true, methods);
 	}
       else
 	{
-	  tmp = immed_double_const (BITS_PER_WORD - 1, 0, op1_mode);
+	  tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD - 1,
+							   op1_mode), op1_mode);
 	  tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
 				       0, true, methods);
 	}
@@ -1035,7 +1037,8 @@ expand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
      is true when the effective shift value is less than BITS_PER_WORD.
      Set SUPERWORD_OP1 to the shift count that should be used to shift
      OUTOF_INPUT into INTO_TARGET when the condition is false.  */
-  tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
+  tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD, op1_mode),
+			      op1_mode);
   if (!CONSTANT_P (op1) && shift_mask == BITS_PER_WORD - 1)
     {
       /* Set CMP1 to OP1 & BITS_PER_WORD.  The result is zero iff OP1
@@ -2885,7 +2888,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
   const struct real_format *fmt;
   int bitpos, word, nwords, i;
   enum machine_mode imode;
-  double_int mask;
+  wide_int mask;
   rtx temp, insns;
 
   /* The format has to have a simple sign bit.  */
@@ -2921,7 +2924,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
       nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
     }
 
-  mask = double_int_zero.set_bit (bitpos);
+  mask = wide_int::set_bit_in_zero (bitpos, imode);
   if (code == ABS)
     mask = ~mask;
 
@@ -2943,7 +2946,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
 	    {
 	      temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
 				   op0_piece,
-				   immed_double_int_const (mask, imode),
+				   immed_wide_int_const (mask, imode),
 				   targ_piece, 1, OPTAB_LIB_WIDEN);
 	      if (temp != targ_piece)
 		emit_move_insn (targ_piece, temp);
@@ -2961,7 +2964,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
     {
       temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
 			   gen_lowpart (imode, op0),
-			   immed_double_int_const (mask, imode),
+			   immed_wide_int_const (mask, imode),
 		           gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
       target = lowpart_subreg_maybe_copy (mode, temp, imode);
 
@@ -3560,7 +3563,7 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
     }
   else
     {
-      double_int mask;
+      wide_int mask;
 
       if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
 	{
@@ -3582,10 +3585,9 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 	  op1 = operand_subword_force (op1, word, mode);
 	}
 
-      mask = double_int_zero.set_bit (bitpos);
-
+      mask = wide_int::set_bit_in_zero (bitpos, imode);
       sign = expand_binop (imode, and_optab, op1,
-			   immed_double_int_const (mask, imode),
+			   immed_wide_int_const (mask, imode),
 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
 
@@ -3629,7 +3631,7 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 		     int bitpos, bool op0_is_abs)
 {
   enum machine_mode imode;
-  double_int mask;
+  wide_int mask, nmask;
   int word, nwords, i;
   rtx temp, insns;
 
@@ -3653,7 +3655,7 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
       nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
     }
 
-  mask = double_int_zero.set_bit (bitpos);
+  mask = wide_int::set_bit_in_zero (bitpos, imode);
 
   if (target == 0
       || target == op0
@@ -3673,14 +3675,16 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 	  if (i == word)
 	    {
 	      if (!op0_is_abs)
-		op0_piece
-		  = expand_binop (imode, and_optab, op0_piece,
-				  immed_double_int_const (~mask, imode),
-				  NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
+		{
+		  nmask = ~mask;
+  		  op0_piece
+		    = expand_binop (imode, and_optab, op0_piece,
+				    immed_wide_int_const (nmask, imode),
+				    NULL_RTX, 1, OPTAB_LIB_WIDEN);
+		}
 	      op1 = expand_binop (imode, and_optab,
 				  operand_subword_force (op1, i, mode),
-				  immed_double_int_const (mask, imode),
+				  immed_wide_int_const (mask, imode),
 				  NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
 	      temp = expand_binop (imode, ior_optab, op0_piece, op1,
@@ -3700,15 +3704,17 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
   else
     {
       op1 = expand_binop (imode, and_optab, gen_lowpart (imode, op1),
-		          immed_double_int_const (mask, imode),
+		          immed_wide_int_const (mask, imode),
 		          NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
       op0 = gen_lowpart (imode, op0);
       if (!op0_is_abs)
-	op0 = expand_binop (imode, and_optab, op0,
-			    immed_double_int_const (~mask, imode),
-			    NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
+	{
+	  nmask = ~mask;
+	  op0 = expand_binop (imode, and_optab, op0,
+			      immed_wide_int_const (nmask, imode),
+			      NULL_RTX, 1, OPTAB_LIB_WIDEN);
+	}
       temp = expand_binop (imode, ior_optab, op0, op1,
 			   gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
       target = lowpart_subreg_maybe_copy (mode, temp, imode);
diff --git a/gcc/postreload.c b/gcc/postreload.c
index 33462e4..b899fe1 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -295,27 +295,25 @@ reload_cse_simplify_set (rtx set, rtx insn)
 #ifdef LOAD_EXTEND_OP
 	  if (extend_op != UNKNOWN)
 	    {
-	      HOST_WIDE_INT this_val;
+	      wide_int result;
 
-	      /* ??? I'm lazy and don't wish to handle CONST_DOUBLE.  Other
-		 constants, such as SYMBOL_REF, cannot be extended.  */
-	      if (!CONST_INT_P (this_rtx))
+	      if (!CONST_SCALAR_INT_P (this_rtx))
 		continue;
 
-	      this_val = INTVAL (this_rtx);
 	      switch (extend_op)
 		{
 		case ZERO_EXTEND:
-		  this_val &= GET_MODE_MASK (GET_MODE (src));
+		  result = (wide_int::from_rtx (this_rtx, GET_MODE (src))
+			    .zext (word_mode));
 		  break;
 		case SIGN_EXTEND:
-		  /* ??? In theory we're already extended.  */
-		  if (this_val == trunc_int_for_mode (this_val, GET_MODE (src)))
-		    break;
+		  result = (wide_int::from_rtx (this_rtx, GET_MODE (src))
+			    .sext (word_mode));
+		  break;
 		default:
 		  gcc_unreachable ();
 		}
-	      this_rtx = GEN_INT (this_val);
+	      this_rtx = immed_wide_int_const (result, GET_MODE (src));
 	    }
 #endif
 	  this_cost = set_src_cost (this_rtx, speed);
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index d2bda9e..3620bd6 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -612,6 +612,12 @@ print_rtx (const_rtx in_rtx)
 	  fprintf (outfile, " [%s]", s);
 	}
       break;
+
+    case CONST_WIDE_INT:
+      if (! flag_simple)
+	fprintf (outfile, " ");
+      hwivec_output_hex (outfile, CONST_WIDE_INT_VEC (in_rtx));
+      break;
 #endif
 
     case CODE_LABEL:
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index cd58b1f..a73a41b 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -806,6 +806,29 @@ validate_const_int (const char *string)
     fatal_with_file_and_line ("invalid decimal constant \"%s\"\n", string);
 }
 
+static void
+validate_const_wide_int (const char *string)
+{
+  const char *cp;
+  int valid = 1;
+
+  cp = string;
+  while (*cp && ISSPACE (*cp))
+    cp++;
+  /* Skip the leading 0x.  */
+  if (cp[0] == '0' || cp[1] == 'x')
+    cp += 2;
+  else
+    valid = 0;
+  if (*cp == 0)
+    valid = 0;
+  for (; *cp; cp++)
+    if (! ISXDIGIT (*cp))
+      valid = 0;
+  if (!valid)
+    fatal_with_file_and_line ("invalid hex constant \"%s\"\n", string);
+}
+
 /* Record that PTR uses iterator ITERATOR.  */
 
 static void
@@ -1319,6 +1342,56 @@ read_rtx_code (const char *code_name)
 	gcc_unreachable ();
       }
 
+  if (CONST_WIDE_INT_P (return_rtx))
+    {
+      read_name (&name);
+      validate_const_wide_int (name.string);
+      {
+	hwivec hwiv;
+	const char *s = name.string;
+	int len;
+	int index = 0;
+	int gs = HOST_BITS_PER_WIDE_INT/4;
+	int pos;
+	char * buf = XALLOCAVEC (char, gs + 1);
+	unsigned HOST_WIDE_INT wi;
+	int wlen;
+
+	/* Skip the leading spaces.  */
+	while (*s && ISSPACE (*s))
+	  s++;
+
+	/* Skip the leading 0x.  */
+	gcc_assert (s[0] == '0');
+	gcc_assert (s[1] == 'x');
+	s += 2;
+
+	len = strlen (s);
+	pos = len - gs;
+	wlen = (len + gs - 1) / gs;	/* Number of words needed */
+
+	return_rtx = const_wide_int_alloc (wlen);
+
+	hwiv = CONST_WIDE_INT_VEC (return_rtx);
+	while (pos > 0)
+	  {
+#if HOST_BITS_PER_WIDE_INT == 64
+	    sscanf (s + pos, "%16" HOST_WIDE_INT_PRINT "x", &wi);
+#else
+	    sscanf (s + pos, "%8" HOST_WIDE_INT_PRINT "x", &wi);
+#endif
+	    XHWIVEC_ELT (hwiv, index++) = wi;
+	    pos -= gs;
+	  }
+	strncpy (buf, s, gs - pos);
+	buf [gs - pos] = 0;
+	sscanf (buf, "%" HOST_WIDE_INT_PRINT "x", &wi);
+	XHWIVEC_ELT (hwiv, index++) = wi;
+	/* TODO: After reading, do we want to canonicalize with:
+	   value = lookup_const_wide_int (value); ? */
+      }
+    }
+
   c = read_skip_spaces ();
   /* Syntactic sugar for AND and IOR, allowing Lisp-like
      arbitrary number of arguments for them.  */
diff --git a/gcc/recog.c b/gcc/recog.c
index ed359f6..05e08e9 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -1141,7 +1141,7 @@ immediate_operand (rtx op, enum machine_mode mode)
 					    : mode, op));
 }
 
-/* Returns 1 if OP is an operand that is a CONST_INT.  */
+/* Returns 1 if OP is an operand that is a CONST_INT of mode MODE.  */
 
 int
 const_int_operand (rtx op, enum machine_mode mode)
@@ -1156,8 +1156,64 @@ const_int_operand (rtx op, enum machine_mode mode)
   return 1;
 }
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns 1 if OP is an operand that is a CONST_INT or CONST_WIDE_INT
+   of mode MODE.  */
+int
+const_scalar_int_operand (rtx op, enum machine_mode mode)
+{
+  if (!CONST_SCALAR_INT_P (op))
+    return 0;
+
+  if (CONST_INT_P (op))
+    return const_int_operand (op, mode);
+
+  if (mode != VOIDmode)
+    {
+      int prec = GET_MODE_PRECISION (mode);
+      int bitsize = GET_MODE_BITSIZE (mode);
+      
+      if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
+	return 0;
+      
+      if (prec == bitsize)
+	return 1;
+      else
+	{
+	  /* Multiword partial int.  */
+	  HOST_WIDE_INT x 
+	    = CONST_WIDE_INT_ELT (op, CONST_WIDE_INT_NUNITS (op) - 1);
+	  return (wide_int::sext (x, prec & (HOST_BITS_PER_WIDE_INT - 1))
+		  == x);
+	}
+    }
+  return 1;
+}
+
+/* Returns 1 if OP is an operand that is a CONST_WIDE_INT of mode
+   MODE.  This most likely is not as useful as
+   const_scalar_int_operand, but is here for consistancy.  */
+int
+const_wide_int_operand (rtx op, enum machine_mode mode)
+{
+  if (!CONST_WIDE_INT_P (op))
+    return 0;
+
+  return const_scalar_int_operand (op, mode);
+}
+
 /* Returns 1 if OP is an operand that is a constant integer or constant
-   floating-point number.  */
+   floating-point number of MODE.  */
+
+int
+const_double_operand (rtx op, enum machine_mode mode)
+{
+  return (GET_CODE (op) == CONST_DOUBLE)
+	  && (GET_MODE (op) == mode || mode == VOIDmode);
+}
+#else
+/* Returns 1 if OP is an operand that is a constant integer or constant
+   floating-point number of MODE.  */
 
 int
 const_double_operand (rtx op, enum machine_mode mode)
@@ -1173,8 +1229,9 @@ const_double_operand (rtx op, enum machine_mode mode)
 	  && (mode == VOIDmode || GET_MODE (op) == mode
 	      || GET_MODE (op) == VOIDmode));
 }
-
-/* Return 1 if OP is a general operand that is not an immediate operand.  */
+#endif
+/* Return 1 if OP is a general operand that is not an immediate
+   operand of mode MODE.  */
 
 int
 nonimmediate_operand (rtx op, enum machine_mode mode)
@@ -1182,7 +1239,8 @@ nonimmediate_operand (rtx op, enum machine_mode mode)
   return (general_operand (op, mode) && ! CONSTANT_P (op));
 }
 
-/* Return 1 if OP is a register reference or immediate value of mode MODE.  */
+/* Return 1 if OP is a register reference or immediate value of mode
+   MODE.  */
 
 int
 nonmemory_operand (rtx op, enum machine_mode mode)
diff --git a/gcc/rtl.c b/gcc/rtl.c
index b2d88f7..074e425 100644
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -109,7 +109,7 @@ const enum rtx_class rtx_class[NUM_RTX_CODE] = {
 const unsigned char rtx_code_size[NUM_RTX_CODE] = {
 #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)				\
   (((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE			\
-    || (ENUM) == CONST_FIXED)						\
+    || (ENUM) == CONST_FIXED || (ENUM) == CONST_WIDE_INT)		\
    ? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT)	\
    : RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (rtunion)),
 
@@ -181,18 +181,24 @@ shallow_copy_rtvec (rtvec vec)
 unsigned int
 rtx_size (const_rtx x)
 {
+  if (CONST_WIDE_INT_P (x))
+    return (RTX_HDR_SIZE
+	    + sizeof (struct hwivec_def)
+	    + ((CONST_WIDE_INT_NUNITS (x) - 1)
+	       * sizeof (HOST_WIDE_INT)));
   if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_HAS_BLOCK_INFO_P (x))
     return RTX_HDR_SIZE + sizeof (struct block_symbol);
   return RTX_CODE_SIZE (GET_CODE (x));
 }
 
-/* Allocate an rtx of code CODE.  The CODE is stored in the rtx;
-   all the rest is initialized to zero.  */
+/* Allocate an rtx of code CODE with EXTRA bytes in it.  The CODE is
+   stored in the rtx; all the rest is initialized to zero.  */
 
 rtx
-rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
+rtx_alloc_stat_v (RTX_CODE code MEM_STAT_DECL, int extra)
 {
-  rtx rt = ggc_alloc_rtx_def_stat (RTX_CODE_SIZE (code) PASS_MEM_STAT);
+  rtx rt = ggc_alloc_rtx_def_stat (RTX_CODE_SIZE (code) + extra
+				   PASS_MEM_STAT);
 
   /* We want to clear everything up to the FLD array.  Normally, this
      is one int, but we don't want to assume that and it isn't very
@@ -210,6 +216,29 @@ rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
   return rt;
 }
 
+/* Allocate an rtx of code CODE.  The CODE is stored in the rtx;
+   all the rest is initialized to zero.  */
+
+rtx
+rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
+{
+  return rtx_alloc_stat_v (code PASS_MEM_STAT, 0);
+}
+
+/* Write the wide constant OP0 to OUTFILE.  */
+
+void
+hwivec_output_hex (FILE *outfile, const_hwivec op0)
+{
+  int i = HWI_GET_NUM_ELEM (op0);
+  gcc_assert (i > 0);
+  if (XHWIVEC_ELT (op0, i-1) == 0)
+    fprintf (outfile, "0x");
+  fprintf (outfile, HOST_WIDE_INT_PRINT_HEX, XHWIVEC_ELT (op0, --i));
+  while (--i >= 0)
+    fprintf (outfile, HOST_WIDE_INT_PRINT_PADDED_HEX, XHWIVEC_ELT (op0, i));
+}
+
 \f
 /* Return true if ORIG is a sharable CONST.  */
 
@@ -428,7 +457,6 @@ rtx_equal_p_cb (const_rtx x, const_rtx y, rtx_equal_p_callback_function cb)
 	  if (XWINT (x, i) != XWINT (y, i))
 	    return 0;
 	  break;
-
 	case 'n':
 	case 'i':
 	  if (XINT (x, i) != XINT (y, i))
@@ -646,6 +674,10 @@ iterative_hash_rtx (const_rtx x, hashval_t hash)
       return iterative_hash_object (i, hash);
     case CONST_INT:
       return iterative_hash_object (INTVAL (x), hash);
+    case CONST_WIDE_INT:
+      for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	hash = iterative_hash_object (CONST_WIDE_INT_ELT (x, i), hash);
+      return hash;
     case SYMBOL_REF:
       if (XSTR (x, 0))
 	return iterative_hash (XSTR (x, 0), strlen (XSTR (x, 0)) + 1,
@@ -811,6 +843,16 @@ rtl_check_failed_block_symbol (const char *file, int line, const char *func)
 
 /* XXX Maybe print the vector?  */
 void
+hwivec_check_failed_bounds (const_hwivec r, int n, const char *file, int line,
+			    const char *func)
+{
+  internal_error
+    ("RTL check: access of hwi elt %d of vector with last elt %d in %s, at %s:%d",
+     n, GET_NUM_ELEM (r) - 1, func, trim_filename (file), line);
+}
+
+/* XXX Maybe print the vector?  */
+void
 rtvec_check_failed_bounds (const_rtvec r, int n, const char *file, int line,
 			   const char *func)
 {
diff --git a/gcc/rtl.def b/gcc/rtl.def
index f8aea32..4c5eb00 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -342,6 +342,9 @@ DEF_RTL_EXPR(TRAP_IF, "trap_if", "ee", RTX_EXTRA)
 /* numeric integer constant */
 DEF_RTL_EXPR(CONST_INT, "const_int", "w", RTX_CONST_OBJ)
 
+/* numeric integer constant */
+DEF_RTL_EXPR(CONST_WIDE_INT, "const_wide_int", "", RTX_CONST_OBJ)
+
 /* fixed-point constant */
 DEF_RTL_EXPR(CONST_FIXED, "const_fixed", "www", RTX_CONST_OBJ)
 
diff --git a/gcc/rtl.h b/gcc/rtl.h
index eea80ef..6479513 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "fixed-value.h"
 #include "alias.h"
 #include "hashtab.h"
+#include "wide-int.h"
 #include "flags.h"
 
 /* Value used by some passes to "recognize" noop moves as valid
@@ -249,6 +250,14 @@ struct GTY(()) object_block {
   vec<rtx, va_gc> *anchors;
 };
 
+struct GTY((variable_size)) hwivec_def {
+  int num_elem;		/* number of elements */
+  HOST_WIDE_INT elem[1];
+};
+
+#define HWI_GET_NUM_ELEM(HWIVEC)	((HWIVEC)->num_elem)
+#define HWI_PUT_NUM_ELEM(HWIVEC, NUM)	((HWIVEC)->num_elem = (NUM))
+
 /* RTL expression ("rtx").  */
 
 struct GTY((chain_next ("RTX_NEXT (&%h)"),
@@ -343,6 +352,7 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"),
     struct block_symbol block_sym;
     struct real_value rv;
     struct fixed_value fv;
+    struct hwivec_def hwiv;
   } GTY ((special ("rtx_def"), desc ("GET_CODE (&%0)"))) u;
 };
 
@@ -382,13 +392,13 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"),
    for a variable number of things.  The principle use is inside
    PARALLEL expressions.  */
 
+#define NULL_RTVEC (rtvec) 0
+
 struct GTY((variable_size)) rtvec_def {
   int num_elem;		/* number of elements */
   rtx GTY ((length ("%h.num_elem"))) elem[1];
 };
 
-#define NULL_RTVEC (rtvec) 0
-
 #define GET_NUM_ELEM(RTVEC)		((RTVEC)->num_elem)
 #define PUT_NUM_ELEM(RTVEC, NUM)	((RTVEC)->num_elem = (NUM))
 
@@ -398,12 +408,38 @@ struct GTY((variable_size)) rtvec_def {
 /* Predicate yielding nonzero iff X is an rtx for a memory location.  */
 #define MEM_P(X) (GET_CODE (X) == MEM)
 
+#if TARGET_SUPPORTS_WIDE_INT
+
+/* Match CONST_*s that can represent compile-time constant integers.  */
+#define CASE_CONST_SCALAR_INT \
+   case CONST_INT: \
+   case CONST_WIDE_INT
+
+/* Match CONST_*s for which pointer equality corresponds to value 
+   equality.  */
+#define CASE_CONST_UNIQUE \
+   case CONST_INT: \
+   case CONST_WIDE_INT: \
+   case CONST_DOUBLE: \
+   case CONST_FIXED
+
+/* Match all CONST_* rtxes.  */
+#define CASE_CONST_ANY \
+   case CONST_INT: \
+   case CONST_WIDE_INT: \
+   case CONST_DOUBLE: \
+   case CONST_FIXED: \
+   case CONST_VECTOR
+
+#else
+
 /* Match CONST_*s that can represent compile-time constant integers.  */
 #define CASE_CONST_SCALAR_INT \
    case CONST_INT: \
    case CONST_DOUBLE
 
-/* Match CONST_*s for which pointer equality corresponds to value equality.  */
+/* Match CONST_*s for which pointer equality corresponds to value 
+equality.  */
 #define CASE_CONST_UNIQUE \
    case CONST_INT: \
    case CONST_DOUBLE: \
@@ -415,10 +451,17 @@ struct GTY((variable_size)) rtvec_def {
    case CONST_DOUBLE: \
    case CONST_FIXED: \
    case CONST_VECTOR
+#endif
+
+
+
 
 /* Predicate yielding nonzero iff X is an rtx for a constant integer.  */
 #define CONST_INT_P(X) (GET_CODE (X) == CONST_INT)
 
+/* Predicate yielding nonzero iff X is an rtx for a constant integer.  */
+#define CONST_WIDE_INT_P(X) (GET_CODE (X) == CONST_WIDE_INT)
+
 /* Predicate yielding nonzero iff X is an rtx for a constant fixed-point.  */
 #define CONST_FIXED_P(X) (GET_CODE (X) == CONST_FIXED)
 
@@ -431,8 +474,13 @@ struct GTY((variable_size)) rtvec_def {
   (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == VOIDmode)
 
 /* Predicate yielding true iff X is an rtx for a integer const.  */
+#if TARGET_SUPPORTS_WIDE_INT
+#define CONST_SCALAR_INT_P(X) \
+  (CONST_INT_P (X) || CONST_WIDE_INT_P (X))
+#else
 #define CONST_SCALAR_INT_P(X) \
   (CONST_INT_P (X) || CONST_DOUBLE_AS_INT_P (X))
+#endif
 
 /* Predicate yielding true iff X is an rtx for a double-int.  */
 #define CONST_DOUBLE_AS_FLOAT_P(X) \
@@ -593,6 +641,13 @@ struct GTY((variable_size)) rtvec_def {
 			       __FUNCTION__);				\
      &_rtx->u.hwint[_n]; }))
 
+#define XHWIVEC_ELT(HWIVEC, I) __extension__				\
+(*({ __typeof (HWIVEC) const _hwivec = (HWIVEC); const int _i = (I);	\
+     if (_i < 0 || _i >= HWI_GET_NUM_ELEM (_hwivec))			\
+       hwivec_check_failed_bounds (_hwivec, _i, __FILE__, __LINE__,	\
+				  __FUNCTION__);			\
+     &_hwivec->elem[_i]; }))
+
 #define XCWINT(RTX, N, C) __extension__					\
 (*({ __typeof (RTX) const _rtx = (RTX);					\
      if (GET_CODE (_rtx) != (C))					\
@@ -629,6 +684,11 @@ struct GTY((variable_size)) rtvec_def {
 				    __FUNCTION__);			\
    &_symbol->u.block_sym; })
 
+#define HWIVEC_CHECK(RTX,C) __extension__				\
+({ __typeof (RTX) const _symbol = (RTX);				\
+   RTL_CHECKC1 (_symbol, 0, C);						\
+   &_symbol->u.hwiv; })
+
 extern void rtl_check_failed_bounds (const_rtx, int, const char *, int,
 				     const char *)
     ATTRIBUTE_NORETURN;
@@ -649,6 +709,9 @@ extern void rtl_check_failed_code_mode (const_rtx, enum rtx_code, enum machine_m
     ATTRIBUTE_NORETURN;
 extern void rtl_check_failed_block_symbol (const char *, int, const char *)
     ATTRIBUTE_NORETURN;
+extern void hwivec_check_failed_bounds (const_rtvec, int, const char *, int,
+					const char *)
+    ATTRIBUTE_NORETURN;
 extern void rtvec_check_failed_bounds (const_rtvec, int, const char *, int,
 				       const char *)
     ATTRIBUTE_NORETURN;
@@ -661,12 +724,14 @@ extern void rtvec_check_failed_bounds (const_rtvec, int, const char *, int,
 #define RTL_CHECKC2(RTX, N, C1, C2) ((RTX)->u.fld[N])
 #define RTVEC_ELT(RTVEC, I)	    ((RTVEC)->elem[I])
 #define XWINT(RTX, N)		    ((RTX)->u.hwint[N])
+#define XHWIVEC_ELT(HWIVEC, I)	    ((HWIVEC)->elem[I])
 #define XCWINT(RTX, N, C)	    ((RTX)->u.hwint[N])
 #define XCMWINT(RTX, N, C, M)	    ((RTX)->u.hwint[N])
 #define XCNMWINT(RTX, N, C, M)	    ((RTX)->u.hwint[N])
 #define XCNMPRV(RTX, C, M)	    (&(RTX)->u.rv)
 #define XCNMPFV(RTX, C, M)	    (&(RTX)->u.fv)
 #define BLOCK_SYMBOL_CHECK(RTX)	    (&(RTX)->u.block_sym)
+#define HWIVEC_CHECK(RTX,C)	    (&(RTX)->u.hwiv)
 
 #endif
 
@@ -809,8 +874,8 @@ extern void rtl_check_failed_flag (const char *, const_rtx, const char *,
 #define XCCFI(RTX, N, C)      (RTL_CHECKC1 (RTX, N, C).rt_cfi)
 #define XCCSELIB(RTX, N, C)   (RTL_CHECKC1 (RTX, N, C).rt_cselib)
 
-#define XCVECEXP(RTX, N, M, C)	RTVEC_ELT (XCVEC (RTX, N, C), M)
-#define XCVECLEN(RTX, N, C)	GET_NUM_ELEM (XCVEC (RTX, N, C))
+#define XCVECEXP(RTX, N, M, C) RTVEC_ELT (XCVEC (RTX, N, C), M)
+#define XCVECLEN(RTX, N, C)    GET_NUM_ELEM (XCVEC (RTX, N, C))
 
 #define XC2EXP(RTX, N, C1, C2)      (RTL_CHECKC2 (RTX, N, C1, C2).rt_rtx)
 \f
@@ -1151,9 +1216,19 @@ rhs_regno (const_rtx x)
 #define INTVAL(RTX) XCWINT(RTX, 0, CONST_INT)
 #define UINTVAL(RTX) ((unsigned HOST_WIDE_INT) INTVAL (RTX))
 
+/* For a CONST_WIDE_INT, CONST_WIDE_INT_NUNITS is the number of
+   elements actually needed to represent the constant.
+   CONST_WIDE_INT_ELT gets one of the elements.  0 is the least
+   significant HOST_WIDE_INT.  */
+#define CONST_WIDE_INT_VEC(RTX) HWIVEC_CHECK (RTX, CONST_WIDE_INT)
+#define CONST_WIDE_INT_NUNITS(RTX) HWI_GET_NUM_ELEM (CONST_WIDE_INT_VEC (RTX))
+#define CONST_WIDE_INT_ELT(RTX, N) XHWIVEC_ELT (CONST_WIDE_INT_VEC (RTX), N) 
+
 /* For a CONST_DOUBLE:
+#if TARGET_SUPPORTS_WIDE_INT == 0
    For a VOIDmode, there are two integers CONST_DOUBLE_LOW is the
      low-order word and ..._HIGH the high-order.
+#endif
    For a float, there is a REAL_VALUE_TYPE structure, and
      CONST_DOUBLE_REAL_VALUE(r) is a pointer to it.  */
 #define CONST_DOUBLE_LOW(r) XCMWINT (r, 0, CONST_DOUBLE, VOIDmode)
@@ -1308,6 +1383,34 @@ struct address_info {
   bool autoinc_p;
 };
 
+#ifndef GENERATOR_FILE
+/* Overload of to_shwi2 function in wide-int.h for rtl.  This cannot be
+   in wide-int.h because of circular includes.  */
+
+inline const HOST_WIDE_INT* wide_int::to_shwi2 (HOST_WIDE_INT *s ATTRIBUTE_UNUSED, int *l,
+			       rtx rcst)
+{
+  switch (GET_CODE (rcst))
+    {
+    case CONST_INT:
+      *l = 1;
+      return &INTVAL (rcst);
+      
+    case CONST_WIDE_INT:
+      *l = CONST_WIDE_INT_NUNITS (rcst);
+      return &CONST_WIDE_INT_ELT (rcst, 0);
+      
+    case CONST_DOUBLE:
+      *l = 2;
+      return &CONST_DOUBLE_LOW (rcst);
+      
+    default:
+      gcc_unreachable ();
+    }
+}
+#endif
+
+
 extern void init_rtlanal (void);
 extern int rtx_cost (rtx, enum rtx_code, int, bool);
 extern int address_cost (rtx, enum machine_mode, addr_space_t, bool);
@@ -1758,6 +1861,12 @@ extern rtx plus_constant (enum machine_mode, rtx, HOST_WIDE_INT);
 /* In rtl.c */
 extern rtx rtx_alloc_stat (RTX_CODE MEM_STAT_DECL);
 #define rtx_alloc(c) rtx_alloc_stat (c MEM_STAT_INFO)
+extern rtx rtx_alloc_stat_v (RTX_CODE MEM_STAT_DECL, int);
+#define rtx_alloc_v(c, SZ) rtx_alloc_stat_v (c MEM_STAT_INFO, SZ)
+#define const_wide_int_alloc(NWORDS)				\
+  rtx_alloc_v (CONST_WIDE_INT,					\
+	       (sizeof (struct hwivec_def)			\
+		+ ((NWORDS)-1) * sizeof (HOST_WIDE_INT)))	\
 
 extern rtvec rtvec_alloc (int);
 extern rtvec shallow_copy_rtvec (rtvec);
@@ -1814,10 +1923,17 @@ extern void start_sequence (void);
 extern void push_to_sequence (rtx);
 extern void push_to_sequence2 (rtx, rtx);
 extern void end_sequence (void);
+#if TARGET_SUPPORTS_WIDE_INT == 0
 extern double_int rtx_to_double_int (const_rtx);
-extern rtx immed_double_int_const (double_int, enum machine_mode);
+#endif
+extern void hwivec_output_hex (FILE *, const_hwivec);
+#ifndef GENERATOR_FILE
+extern rtx immed_wide_int_const (const wide_int &cst, enum machine_mode mode);
+#endif
+#if TARGET_SUPPORTS_WIDE_INT == 0
 extern rtx immed_double_const (HOST_WIDE_INT, HOST_WIDE_INT,
 			       enum machine_mode);
+#endif
 
 /* In loop-iv.c  */
 
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index b198685..0fe1d0e 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -3091,6 +3091,8 @@ commutative_operand_precedence (rtx op)
   /* Constants always come the second operand.  Prefer "nice" constants.  */
   if (code == CONST_INT)
     return -8;
+  if (code == CONST_WIDE_INT)
+    return -8;
   if (code == CONST_DOUBLE)
     return -7;
   if (code == CONST_FIXED)
@@ -3103,6 +3105,8 @@ commutative_operand_precedence (rtx op)
     case RTX_CONST_OBJ:
       if (code == CONST_INT)
         return -6;
+      if (code == CONST_WIDE_INT)
+        return -6;
       if (code == CONST_DOUBLE)
         return -5;
       if (code == CONST_FIXED)
@@ -5289,7 +5293,10 @@ get_address_mode (rtx mem)
 /* Split up a CONST_DOUBLE or integer constant rtx
    into two rtx's for single words,
    storing in *FIRST the word that comes first in memory in the target
-   and in *SECOND the other.  */
+   and in *SECOND the other. 
+
+   TODO: This function needs to be rewritten to work on any size
+   integer.  */
 
 void
 split_double (rtx value, rtx *first, rtx *second)
@@ -5366,6 +5373,22 @@ split_double (rtx value, rtx *first, rtx *second)
 	    }
 	}
     }
+  else if (GET_CODE (value) == CONST_WIDE_INT)
+    {
+      /* All of this is scary code and needs to be converted to
+	 properly work with any size integer.  */
+      gcc_assert (CONST_WIDE_INT_NUNITS (value) == 2);
+      if (WORDS_BIG_ENDIAN)
+	{
+	  *first = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+	  *second = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+	}
+      else
+	{
+	  *first = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+	  *second = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+	}
+    }
   else if (!CONST_DOUBLE_P (value))
     {
       if (WORDS_BIG_ENDIAN)
diff --git a/gcc/sched-vis.c b/gcc/sched-vis.c
index 763230c..979aab1 100644
--- a/gcc/sched-vis.c
+++ b/gcc/sched-vis.c
@@ -432,6 +432,23 @@ print_value (pretty_printer *pp, const_rtx x, int verbose)
       pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
 		 (unsigned HOST_WIDE_INT) INTVAL (x));
       break;
+
+    case CONST_WIDE_INT:
+      {
+	const char *sep = "<";
+	int i;
+	for (i = CONST_WIDE_INT_NUNITS (x) - 1; i >= 0; i--)
+	  {
+	    pp_string (pp, sep);
+	    sep = ",";
+	    sprintf (tmp, HOST_WIDE_INT_PRINT_HEX,
+		     (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, i));
+	    pp_string (pp, tmp);
+	  }
+        pp_greater (pp);
+      }
+      break;
+
     case CONST_DOUBLE:
       if (FLOAT_MODE_P (GET_MODE (x)))
 	{
diff --git a/gcc/sel-sched-ir.c b/gcc/sel-sched-ir.c
index 47e7695..828cac3 100644
--- a/gcc/sel-sched-ir.c
+++ b/gcc/sel-sched-ir.c
@@ -1141,10 +1141,10 @@ lhs_and_rhs_separable_p (rtx lhs, rtx rhs)
   if (lhs == NULL || rhs == NULL)
     return false;
 
-  /* Do not schedule CONST, CONST_INT and CONST_DOUBLE etc as rhs: no point
-     to use reg, if const can be used.  Moreover, scheduling const as rhs may
-     lead to mode mismatch cause consts don't have modes but they could be
-     merged from branches where the same const used in different modes.  */
+  /* Do not schedule constants as rhs: no point to use reg, if const
+     can be used.  Moreover, scheduling const as rhs may lead to mode
+     mismatch cause consts don't have modes but they could be merged
+     from branches where the same const used in different modes.  */
   if (CONSTANT_P (rhs))
     return false;
 
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 791f91a..54a34ff 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -86,6 +86,22 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
   if (width <= HOST_BITS_PER_WIDE_INT
       && CONST_INT_P (x))
     val = INTVAL (x);
+#if TARGET_SUPPORTS_WIDE_INT
+  else if (CONST_WIDE_INT_P (x))
+    {
+      unsigned int i;
+      unsigned int elts = CONST_WIDE_INT_NUNITS (x);
+      if (elts != (width + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+	return false;
+      for (i = 0; i < elts - 1; i++)
+	if (CONST_WIDE_INT_ELT (x, i) != 0)
+	  return false;
+      val = CONST_WIDE_INT_ELT (x, elts - 1);
+      width %= HOST_BITS_PER_WIDE_INT;
+      if (width == 0)
+	width = HOST_BITS_PER_WIDE_INT;
+    }
+#else
   else if (width <= HOST_BITS_PER_DOUBLE_INT
 	   && CONST_DOUBLE_AS_INT_P (x)
 	   && CONST_DOUBLE_LOW (x) == 0)
@@ -93,8 +109,9 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
       val = CONST_DOUBLE_HIGH (x);
       width -= HOST_BITS_PER_WIDE_INT;
     }
+#endif
   else
-    /* FIXME: We don't yet have a representation for wider modes.  */
+    /* X is not an integer constant.  */
     return false;
 
   if (width < HOST_BITS_PER_WIDE_INT)
@@ -1496,7 +1513,6 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 				rtx op, enum machine_mode op_mode)
 {
   unsigned int width = GET_MODE_PRECISION (mode);
-  unsigned int op_width = GET_MODE_PRECISION (op_mode);
 
   if (code == VEC_DUPLICATE)
     {
@@ -1570,8 +1586,19 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       if (CONST_INT_P (op))
 	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
       else
+#if TARGET_SUPPORTS_WIDE_INT
+	{
+	  /* The conversion code to floats really want exactly 2 HWIs.
+	     This needs to be fixed.  For now, if the constant is
+	     really big, just return 0 which is safe.  */
+	  if (CONST_WIDE_INT_NUNITS (op) > 2)
+	    return 0;
+	  lv = CONST_WIDE_INT_ELT (op, 0);
+	  hv = CONST_WIDE_INT_ELT (op, 1);
+	}
+#else
 	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
-
+#endif
       REAL_VALUE_FROM_INT (d, lv, hv, mode);
       d = real_value_truncate (mode, d);
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
@@ -1584,8 +1611,19 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       if (CONST_INT_P (op))
 	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
       else
+#if TARGET_SUPPORTS_WIDE_INT
+	{
+	  /* The conversion code to floats really want exactly 2 HWIs.
+	     This needs to be fixed.  For now, if the constant is
+	     really big, just return 0 which is safe.  */
+	  if (CONST_WIDE_INT_NUNITS (op) > 2)
+	    return 0;
+	  lv = CONST_WIDE_INT_ELT (op, 0);
+	  hv = CONST_WIDE_INT_ELT (op, 1);
+	}
+#else
 	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
-
+#endif
       if (op_mode == VOIDmode
 	  || GET_MODE_PRECISION (op_mode) > HOST_BITS_PER_DOUBLE_INT)
 	/* We should never get a negative number.  */
@@ -1598,302 +1636,82 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
 
-  if (CONST_INT_P (op)
-      && width <= HOST_BITS_PER_WIDE_INT && width > 0)
+  if (CONST_SCALAR_INT_P (op) && width > 0)
     {
-      HOST_WIDE_INT arg0 = INTVAL (op);
-      HOST_WIDE_INT val;
+      wide_int result;
+      enum machine_mode imode = op_mode == VOIDmode ? mode : op_mode;
+      wide_int op0 = wide_int::from_rtx (op, imode);
+
+#if TARGET_SUPPORTS_WIDE_INT == 0
+      /* This assert keeps the simplification from producing a result
+	 that cannot be represented in a CONST_DOUBLE but a lot of
+	 upstream callers expect that this function never fails to
+	 simplify something and so you if you added this to the test
+	 above the code would die later anyway.  If this assert
+	 happens, you just need to make the port support wide int.  */
+      gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT); 
+#endif
 
       switch (code)
 	{
 	case NOT:
-	  val = ~ arg0;
+	  result = ~op0;
 	  break;
 
 	case NEG:
-	  val = - arg0;
+	  result = op0.neg ();
 	  break;
 
 	case ABS:
-	  val = (arg0 >= 0 ? arg0 : - arg0);
+	  result = op0.abs ();
 	  break;
 
 	case FFS:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = ffs_hwi (arg0);
+	  result = op0.ffs ();
 	  break;
 
 	case CLZ:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0 && CLZ_DEFINED_VALUE_AT_ZERO (mode, val))
-	    ;
-	  else
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 1;
+	  result = op0.clz ();
 	  break;
 
 	case CLRSB:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0)
-	    val = GET_MODE_PRECISION (mode) - 1;
-	  else if (arg0 >= 0)
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 2;
-	  else if (arg0 < 0)
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (~arg0) - 2;
+	  result = op0.clrsb ();
 	  break;
-
+	  
 	case CTZ:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0)
-	    {
-	      /* Even if the value at zero is undefined, we have to come
-		 up with some replacement.  Seems good enough.  */
-	      if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, val))
-		val = GET_MODE_PRECISION (mode);
-	    }
-	  else
-	    val = ctz_hwi (arg0);
+	  result = op0.ctz ();
 	  break;
 
 	case POPCOUNT:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = 0;
-	  while (arg0)
-	    val++, arg0 &= arg0 - 1;
+	  result = op0.popcount ();
 	  break;
 
 	case PARITY:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = 0;
-	  while (arg0)
-	    val++, arg0 &= arg0 - 1;
-	  val &= 1;
+	  result = op0.parity ();
 	  break;
 
 	case BSWAP:
-	  {
-	    unsigned int s;
-
-	    val = 0;
-	    for (s = 0; s < width; s += 8)
-	      {
-		unsigned int d = width - s - 8;
-		unsigned HOST_WIDE_INT byte;
-		byte = (arg0 >> s) & 0xff;
-		val |= byte << d;
-	      }
-	  }
+	  result = op0.bswap ();
 	  break;
 
 	case TRUNCATE:
-	  val = arg0;
+	  result = op0.zforce_to_size (mode);
 	  break;
 
 	case ZERO_EXTEND:
-	  /* When zero-extending a CONST_INT, we need to know its
-             original mode.  */
-	  gcc_assert (op_mode != VOIDmode);
-	  if (op_width == HOST_BITS_PER_WIDE_INT)
-	    {
-	      /* If we were really extending the mode,
-		 we would have to distinguish between zero-extension
-		 and sign-extension.  */
-	      gcc_assert (width == op_width);
-	      val = arg0;
-	    }
-	  else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
-	    val = arg0 & GET_MODE_MASK (op_mode);
-	  else
-	    return 0;
+	  result = op0.zforce_to_size (mode);
 	  break;
 
 	case SIGN_EXTEND:
-	  if (op_mode == VOIDmode)
-	    op_mode = mode;
-	  op_width = GET_MODE_PRECISION (op_mode);
-	  if (op_width == HOST_BITS_PER_WIDE_INT)
-	    {
-	      /* If we were really extending the mode,
-		 we would have to distinguish between zero-extension
-		 and sign-extension.  */
-	      gcc_assert (width == op_width);
-	      val = arg0;
-	    }
-	  else if (op_width < HOST_BITS_PER_WIDE_INT)
-	    {
-	      val = arg0 & GET_MODE_MASK (op_mode);
-	      if (val_signbit_known_set_p (op_mode, val))
-		val |= ~GET_MODE_MASK (op_mode);
-	    }
-	  else
-	    return 0;
+	  result = op0.sforce_to_size (mode);
 	  break;
 
 	case SQRT:
-	case FLOAT_EXTEND:
-	case FLOAT_TRUNCATE:
-	case SS_TRUNCATE:
-	case US_TRUNCATE:
-	case SS_NEG:
-	case US_NEG:
-	case SS_ABS:
-	  return 0;
-
-	default:
-	  gcc_unreachable ();
-	}
-
-      return gen_int_mode (val, mode);
-    }
-
-  /* We can do some operations on integer CONST_DOUBLEs.  Also allow
-     for a DImode operation on a CONST_INT.  */
-  else if (width <= HOST_BITS_PER_DOUBLE_INT
-	   && (CONST_DOUBLE_AS_INT_P (op) || CONST_INT_P (op)))
-    {
-      double_int first, value;
-
-      if (CONST_DOUBLE_AS_INT_P (op))
-	first = double_int::from_pair (CONST_DOUBLE_HIGH (op),
-				       CONST_DOUBLE_LOW (op));
-      else
-	first = double_int::from_shwi (INTVAL (op));
-
-      switch (code)
-	{
-	case NOT:
-	  value = ~first;
-	  break;
-
-	case NEG:
-	  value = -first;
-	  break;
-
-	case ABS:
-	  if (first.is_negative ())
-	    value = -first;
-	  else
-	    value = first;
-	  break;
-
-	case FFS:
-	  value.high = 0;
-	  if (first.low != 0)
-	    value.low = ffs_hwi (first.low);
-	  else if (first.high != 0)
-	    value.low = HOST_BITS_PER_WIDE_INT + ffs_hwi (first.high);
-	  else
-	    value.low = 0;
-	  break;
-
-	case CLZ:
-	  value.high = 0;
-	  if (first.high != 0)
-	    value.low = GET_MODE_PRECISION (mode) - floor_log2 (first.high) - 1
-	              - HOST_BITS_PER_WIDE_INT;
-	  else if (first.low != 0)
-	    value.low = GET_MODE_PRECISION (mode) - floor_log2 (first.low) - 1;
-	  else if (! CLZ_DEFINED_VALUE_AT_ZERO (mode, value.low))
-	    value.low = GET_MODE_PRECISION (mode);
-	  break;
-
-	case CTZ:
-	  value.high = 0;
-	  if (first.low != 0)
-	    value.low = ctz_hwi (first.low);
-	  else if (first.high != 0)
-	    value.low = HOST_BITS_PER_WIDE_INT + ctz_hwi (first.high);
-	  else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, value.low))
-	    value.low = GET_MODE_PRECISION (mode);
-	  break;
-
-	case POPCOUNT:
-	  value = double_int_zero;
-	  while (first.low)
-	    {
-	      value.low++;
-	      first.low &= first.low - 1;
-	    }
-	  while (first.high)
-	    {
-	      value.low++;
-	      first.high &= first.high - 1;
-	    }
-	  break;
-
-	case PARITY:
-	  value = double_int_zero;
-	  while (first.low)
-	    {
-	      value.low++;
-	      first.low &= first.low - 1;
-	    }
-	  while (first.high)
-	    {
-	      value.low++;
-	      first.high &= first.high - 1;
-	    }
-	  value.low &= 1;
-	  break;
-
-	case BSWAP:
-	  {
-	    unsigned int s;
-
-	    value = double_int_zero;
-	    for (s = 0; s < width; s += 8)
-	      {
-		unsigned int d = width - s - 8;
-		unsigned HOST_WIDE_INT byte;
-
-		if (s < HOST_BITS_PER_WIDE_INT)
-		  byte = (first.low >> s) & 0xff;
-		else
-		  byte = (first.high >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff;
-
-		if (d < HOST_BITS_PER_WIDE_INT)
-		  value.low |= byte << d;
-		else
-		  value.high |= byte << (d - HOST_BITS_PER_WIDE_INT);
-	      }
-	  }
-	  break;
-
-	case TRUNCATE:
-	  /* This is just a change-of-mode, so do nothing.  */
-	  value = first;
-	  break;
-
-	case ZERO_EXTEND:
-	  gcc_assert (op_mode != VOIDmode);
-
-	  if (op_width > HOST_BITS_PER_WIDE_INT)
-	    return 0;
-
-	  value = double_int::from_uhwi (first.low & GET_MODE_MASK (op_mode));
-	  break;
-
-	case SIGN_EXTEND:
-	  if (op_mode == VOIDmode
-	      || op_width > HOST_BITS_PER_WIDE_INT)
-	    return 0;
-	  else
-	    {
-	      value.low = first.low & GET_MODE_MASK (op_mode);
-	      if (val_signbit_known_set_p (op_mode, value.low))
-		value.low |= ~GET_MODE_MASK (op_mode);
-
-	      value.high = HWI_SIGN_EXTEND (value.low);
-	    }
-	  break;
-
-	case SQRT:
-	  return 0;
-
 	default:
 	  return 0;
 	}
 
-      return immed_double_int_const (value, mode);
+      return immed_wide_int_const (result, mode);
     }
 
   else if (CONST_DOUBLE_AS_FLOAT_P (op) 
@@ -1945,7 +1763,6 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	}
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
-
   else if (CONST_DOUBLE_AS_FLOAT_P (op)
 	   && SCALAR_FLOAT_MODE_P (GET_MODE (op))
 	   && GET_MODE_CLASS (mode) == MODE_INT
@@ -1958,9 +1775,12 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 
       /* This was formerly used only for non-IEEE float.
 	 eggert@twinsun.com says it is safe for IEEE also.  */
-      HOST_WIDE_INT xh, xl, th, tl;
+      HOST_WIDE_INT th, tl;
       REAL_VALUE_TYPE x, t;
+      wide_int wc;
       REAL_VALUE_FROM_CONST_DOUBLE (x, op);
+      HOST_WIDE_INT tmp[2];
+
       switch (code)
 	{
 	case FIX:
@@ -1982,8 +1802,8 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  real_from_integer (&t, VOIDmode, tl, th, 0);
 	  if (REAL_VALUES_LESS (t, x))
 	    {
-	      xh = th;
-	      xl = tl;
+	      tmp[1] = th;
+	      tmp[0] = tl;
 	      break;
 	    }
 
@@ -2002,11 +1822,11 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  real_from_integer (&t, VOIDmode, tl, th, 0);
 	  if (REAL_VALUES_LESS (x, t))
 	    {
-	      xh = th;
-	      xl = tl;
+	      tmp[1] = th;
+	      tmp[0] = tl;
 	      break;
 	    }
-	  REAL_VALUE_TO_INT (&xl, &xh, x);
+	  REAL_VALUE_TO_INT (&tmp[0], &tmp[1], x);
 	  break;
 
 	case UNSIGNED_FIX:
@@ -2033,18 +1853,19 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  real_from_integer (&t, VOIDmode, tl, th, 1);
 	  if (REAL_VALUES_LESS (t, x))
 	    {
-	      xh = th;
-	      xl = tl;
+	      tmp[1] = th;
+	      tmp[0] = tl;
 	      break;
 	    }
 
-	  REAL_VALUE_TO_INT (&xl, &xh, x);
+	  REAL_VALUE_TO_INT (&tmp[0], &tmp[1], x);
 	  break;
 
 	default:
 	  gcc_unreachable ();
 	}
-      return immed_double_const (xl, xh, mode);
+      wc = wide_int::from_array (tmp, 2, mode);
+      return immed_wide_int_const (wc, mode);
     }
 
   return NULL_RTX;
@@ -2204,49 +2025,50 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       if (SCALAR_INT_MODE_P (mode))
 	{
-	  double_int coeff0, coeff1;
+	  wide_int coeff0;
+	  wide_int coeff1;
 	  rtx lhs = op0, rhs = op1;
 
-	  coeff0 = double_int_one;
-	  coeff1 = double_int_one;
+	  coeff0 = wide_int::one (mode);
+	  coeff1 = wide_int::one (mode);
 
 	  if (GET_CODE (lhs) == NEG)
 	    {
-	      coeff0 = double_int_minus_one;
+	      coeff0 = wide_int::minus_one (mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == MULT
-		   && CONST_INT_P (XEXP (lhs, 1)))
+		   && CONST_SCALAR_INT_P (XEXP (lhs, 1)))
 	    {
-	      coeff0 = double_int::from_shwi (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::from_rtx (XEXP (lhs, 1), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == ASHIFT
 		   && CONST_INT_P (XEXP (lhs, 1))
                    && INTVAL (XEXP (lhs, 1)) >= 0
-		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (lhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff0 = double_int_zero.set_bit (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::set_bit_in_zero (INTVAL (XEXP (lhs, 1)), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 
 	  if (GET_CODE (rhs) == NEG)
 	    {
-	      coeff1 = double_int_minus_one;
+	      coeff1 = wide_int::minus_one (mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == MULT
 		   && CONST_INT_P (XEXP (rhs, 1)))
 	    {
-	      coeff1 = double_int::from_shwi (INTVAL (XEXP (rhs, 1)));
+	      coeff1 = wide_int::from_rtx (XEXP (rhs, 1), mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == ASHIFT
 		   && CONST_INT_P (XEXP (rhs, 1))
 		   && INTVAL (XEXP (rhs, 1)) >= 0
-		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (rhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff1 = double_int_zero.set_bit (INTVAL (XEXP (rhs, 1)));
+	      coeff1 = wide_int::set_bit_in_zero (INTVAL (XEXP (rhs, 1)), mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 
@@ -2254,11 +2076,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	    {
 	      rtx orig = gen_rtx_PLUS (mode, op0, op1);
 	      rtx coeff;
-	      double_int val;
 	      bool speed = optimize_function_for_speed_p (cfun);
 
-	      val = coeff0 + coeff1;
-	      coeff = immed_double_int_const (val, mode);
+	      coeff = immed_wide_int_const (coeff0 + coeff1, mode);
 
 	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
 	      return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
@@ -2380,50 +2200,52 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       if (SCALAR_INT_MODE_P (mode))
 	{
-	  double_int coeff0, negcoeff1;
+	  wide_int coeff0;
+	  wide_int negcoeff1;
 	  rtx lhs = op0, rhs = op1;
 
-	  coeff0 = double_int_one;
-	  negcoeff1 = double_int_minus_one;
+	  coeff0 = wide_int::one (mode);
+	  negcoeff1 = wide_int::minus_one (mode);
 
 	  if (GET_CODE (lhs) == NEG)
 	    {
-	      coeff0 = double_int_minus_one;
+	      coeff0 = wide_int::minus_one (mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == MULT
-		   && CONST_INT_P (XEXP (lhs, 1)))
+		   && CONST_SCALAR_INT_P (XEXP (lhs, 1)))
 	    {
-	      coeff0 = double_int::from_shwi (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::from_rtx (XEXP (lhs, 1), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == ASHIFT
 		   && CONST_INT_P (XEXP (lhs, 1))
 		   && INTVAL (XEXP (lhs, 1)) >= 0
-		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (lhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff0 = double_int_zero.set_bit (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::set_bit_in_zero (INTVAL (XEXP (lhs, 1)), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 
 	  if (GET_CODE (rhs) == NEG)
 	    {
-	      negcoeff1 = double_int_one;
+	      negcoeff1 = wide_int::one (mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == MULT
 		   && CONST_INT_P (XEXP (rhs, 1)))
 	    {
-	      negcoeff1 = double_int::from_shwi (-INTVAL (XEXP (rhs, 1)));
+	      negcoeff1 = wide_int::from_rtx (XEXP (rhs, 1), mode).neg ();
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == ASHIFT
 		   && CONST_INT_P (XEXP (rhs, 1))
 		   && INTVAL (XEXP (rhs, 1)) >= 0
-		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (rhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      negcoeff1 = double_int_zero.set_bit (INTVAL (XEXP (rhs, 1)));
-	      negcoeff1 = -negcoeff1;
+	      negcoeff1 = wide_int::set_bit_in_zero (INTVAL (XEXP (rhs, 1)),
+						    mode);
+	      negcoeff1 = negcoeff1.neg ();
 	      rhs = XEXP (rhs, 0);
 	    }
 
@@ -2431,11 +2253,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	    {
 	      rtx orig = gen_rtx_MINUS (mode, op0, op1);
 	      rtx coeff;
-	      double_int val;
 	      bool speed = optimize_function_for_speed_p (cfun);
 
-	      val = coeff0 + negcoeff1;
-	      coeff = immed_double_int_const (val, mode);
+	      coeff = immed_wide_int_const (coeff0 + negcoeff1, mode);
 
 	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
 	      return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
@@ -2587,26 +2407,13 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	  && trueop1 == CONST1_RTX (mode))
 	return op0;
 
-      /* Convert multiply by constant power of two into shift unless
-	 we are still generating RTL.  This test is a kludge.  */
-      if (CONST_INT_P (trueop1)
-	  && (val = exact_log2 (UINTVAL (trueop1))) >= 0
-	  /* If the mode is larger than the host word size, and the
-	     uppermost bit is set, then this isn't a power of two due
-	     to implicit sign extension.  */
-	  && (width <= HOST_BITS_PER_WIDE_INT
-	      || val != HOST_BITS_PER_WIDE_INT - 1))
-	return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
-
-      /* Likewise for multipliers wider than a word.  */
-      if (CONST_DOUBLE_AS_INT_P (trueop1)
-	  && GET_MODE (op0) == mode
-	  && CONST_DOUBLE_LOW (trueop1) == 0
-	  && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0
-	  && (val < HOST_BITS_PER_DOUBLE_INT - 1
-	      || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT))
-	return simplify_gen_binary (ASHIFT, mode, op0,
-				    GEN_INT (val + HOST_BITS_PER_WIDE_INT));
+      /* Convert multiply by constant power of two into shift.  */
+      if (CONST_SCALAR_INT_P (trueop1))
+	{
+	  val = wide_int::from_rtx (trueop1, mode).exact_log2 ().to_shwi ();
+	  if (val >= 0 && val < GET_MODE_BITSIZE (mode))
+	    return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
+	}
 
       /* x*2 is x+x and x*(-1) is -x */
       if (CONST_DOUBLE_AS_FLOAT_P (trueop1)
@@ -3682,9 +3489,9 @@ rtx
 simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 				 rtx op0, rtx op1)
 {
-  HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
-  HOST_WIDE_INT val;
+#if TARGET_SUPPORTS_WIDE_INT == 0
   unsigned int width = GET_MODE_PRECISION (mode);
+#endif
 
   if (VECTOR_MODE_P (mode)
       && code != VEC_CONCAT
@@ -3877,299 +3684,128 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
   /* We can fold some multi-word operations.  */
   if (GET_MODE_CLASS (mode) == MODE_INT
-      && width == HOST_BITS_PER_DOUBLE_INT
-      && (CONST_DOUBLE_AS_INT_P (op0) || CONST_INT_P (op0))
-      && (CONST_DOUBLE_AS_INT_P (op1) || CONST_INT_P (op1)))
+      && CONST_SCALAR_INT_P (op0)
+      && CONST_SCALAR_INT_P (op1))
     {
-      double_int o0, o1, res, tmp;
-      bool overflow;
-
-      o0 = rtx_to_double_int (op0);
-      o1 = rtx_to_double_int (op1);
-
+      wide_int result;
+      wide_int wop0 = wide_int::from_rtx (op0, mode);
+      bool overflow = false;
+      unsigned int bitsize = GET_MODE_BITSIZE (mode);
+
+#if TARGET_SUPPORTS_WIDE_INT == 0
+      /* This assert keeps the simplification from producing a result
+	 that cannot be represented in a CONST_DOUBLE but a lot of
+	 upstream callers expect that this function never fails to
+	 simplify something and so you if you added this to the test
+	 above the code would die later anyway.  If this assert
+	 happens, you just need to make the port support wide int.  */
+      gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT);
+#endif
       switch (code)
 	{
 	case MINUS:
-	  /* A - B == A + (-B).  */
-	  o1 = -o1;
-
-	  /* Fall through....  */
+	  result = wop0 - op1;
+	  break;
 
 	case PLUS:
-	  res = o0 + o1;
+	  result = wop0 + op1;
 	  break;
 
 	case MULT:
-	  res = o0 * o1;
+	  result = wop0 * op1;
 	  break;
 
 	case DIV:
-          res = o0.divmod_with_overflow (o1, false, TRUNC_DIV_EXPR,
-					 &tmp, &overflow);
+	  result = wop0.div_trunc (op1, wide_int::SIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
-
+	  
 	case MOD:
-          tmp = o0.divmod_with_overflow (o1, false, TRUNC_DIV_EXPR,
-					 &res, &overflow);
+	  result = wop0.mod_trunc (op1, wide_int::SIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case UDIV:
-          res = o0.divmod_with_overflow (o1, true, TRUNC_DIV_EXPR,
-					 &tmp, &overflow);
+	  result = wop0.div_trunc (op1, wide_int::UNSIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case UMOD:
-          tmp = o0.divmod_with_overflow (o1, true, TRUNC_DIV_EXPR,
-					 &res, &overflow);
+	  result = wop0.mod_trunc (op1, wide_int::UNSIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case AND:
-	  res = o0 & o1;
+	  result = wop0 & op1;
 	  break;
 
 	case IOR:
-	  res = o0 | o1;
+	  result = wop0 | op1;
 	  break;
 
 	case XOR:
-	  res = o0 ^ o1;
+	  result = wop0 ^ op1;
 	  break;
 
 	case SMIN:
-	  res = o0.smin (o1);
+	  result = wop0.smin (op1);
 	  break;
 
 	case SMAX:
-	  res = o0.smax (o1);
+	  result = wop0.smax (op1);
 	  break;
 
 	case UMIN:
-	  res = o0.umin (o1);
+	  result = wop0.umin (op1);
 	  break;
 
 	case UMAX:
-	  res = o0.umax (o1);
-	  break;
-
-	case LSHIFTRT:   case ASHIFTRT:
-	case ASHIFT:
-	case ROTATE:     case ROTATERT:
-	  {
-	    unsigned HOST_WIDE_INT cnt;
-
-	    if (SHIFT_COUNT_TRUNCATED)
-	      {
-		o1.high = 0; 
-		o1.low &= GET_MODE_PRECISION (mode) - 1;
-	      }
-
-	    if (!o1.fits_uhwi ()
-	        || o1.to_uhwi () >= GET_MODE_PRECISION (mode))
-	      return 0;
-
-	    cnt = o1.to_uhwi ();
-	    unsigned short prec = GET_MODE_PRECISION (mode);
-
-	    if (code == LSHIFTRT || code == ASHIFTRT)
-	      res = o0.rshift (cnt, prec, code == ASHIFTRT);
-	    else if (code == ASHIFT)
-	      res = o0.alshift (cnt, prec);
-	    else if (code == ROTATE)
-	      res = o0.lrotate (cnt, prec);
-	    else /* code == ROTATERT */
-	      res = o0.rrotate (cnt, prec);
-	  }
-	  break;
-
-	default:
-	  return 0;
-	}
-
-      return immed_double_int_const (res, mode);
-    }
-
-  if (CONST_INT_P (op0) && CONST_INT_P (op1)
-      && width <= HOST_BITS_PER_WIDE_INT && width != 0)
-    {
-      /* Get the integer argument values in two forms:
-         zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S.  */
-
-      arg0 = INTVAL (op0);
-      arg1 = INTVAL (op1);
-
-      if (width < HOST_BITS_PER_WIDE_INT)
-        {
-          arg0 &= GET_MODE_MASK (mode);
-          arg1 &= GET_MODE_MASK (mode);
-
-          arg0s = arg0;
-	  if (val_signbit_known_set_p (mode, arg0s))
-	    arg0s |= ~GET_MODE_MASK (mode);
-
-          arg1s = arg1;
-	  if (val_signbit_known_set_p (mode, arg1s))
-	    arg1s |= ~GET_MODE_MASK (mode);
-	}
-      else
-	{
-	  arg0s = arg0;
-	  arg1s = arg1;
-	}
-
-      /* Compute the value of the arithmetic.  */
-
-      switch (code)
-	{
-	case PLUS:
-	  val = arg0s + arg1s;
-	  break;
-
-	case MINUS:
-	  val = arg0s - arg1s;
-	  break;
-
-	case MULT:
-	  val = arg0s * arg1s;
-	  break;
-
-	case DIV:
-	  if (arg1s == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = arg0s / arg1s;
-	  break;
-
-	case MOD:
-	  if (arg1s == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = arg0s % arg1s;
+	  result = wop0.umax (op1);
 	  break;
 
-	case UDIV:
-	  if (arg1 == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = (unsigned HOST_WIDE_INT) arg0 / arg1;
-	  break;
-
-	case UMOD:
-	  if (arg1 == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = (unsigned HOST_WIDE_INT) arg0 % arg1;
-	  break;
-
-	case AND:
-	  val = arg0 & arg1;
-	  break;
-
-	case IOR:
-	  val = arg0 | arg1;
-	  break;
+	case LSHIFTRT:
+	  if (wide_int::from_rtx (op1, mode).neg_p ())
+	    return NULL_RTX;
 
-	case XOR:
-	  val = arg0 ^ arg1;
+	  result = wop0.rshiftu (op1, bitsize, wide_int::TRUNC);
 	  break;
-
-	case LSHIFTRT:
-	case ASHIFT:
+	  
 	case ASHIFTRT:
-	  /* Truncate the shift if SHIFT_COUNT_TRUNCATED, otherwise make sure
-	     the value is in range.  We can't return any old value for
-	     out-of-range arguments because either the middle-end (via
-	     shift_truncation_mask) or the back-end might be relying on
-	     target-specific knowledge.  Nor can we rely on
-	     shift_truncation_mask, since the shift might not be part of an
-	     ashlM3, lshrM3 or ashrM3 instruction.  */
-	  if (SHIFT_COUNT_TRUNCATED)
-	    arg1 = (unsigned HOST_WIDE_INT) arg1 % width;
-	  else if (arg1 < 0 || arg1 >= GET_MODE_BITSIZE (mode))
-	    return 0;
-
-	  val = (code == ASHIFT
-		 ? ((unsigned HOST_WIDE_INT) arg0) << arg1
-		 : ((unsigned HOST_WIDE_INT) arg0) >> arg1);
+	  if (wide_int::from_rtx (op1, mode).neg_p ())
+	    return NULL_RTX;
 
-	  /* Sign-extend the result for arithmetic right shifts.  */
-	  if (code == ASHIFTRT && arg0s < 0 && arg1 > 0)
-	    val |= ((unsigned HOST_WIDE_INT) (-1)) << (width - arg1);
+	  result = wop0.rshifts (op1, bitsize, wide_int::TRUNC);
 	  break;
+	  
+	case ASHIFT:
+	  if (wide_int::from_rtx (op1, mode).neg_p ())
+	    return NULL_RTX;
 
-	case ROTATERT:
-	  if (arg1 < 0)
-	    return 0;
-
-	  arg1 %= width;
-	  val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
-		 | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
+	  result = wop0.lshift (op1, bitsize, wide_int::TRUNC);
 	  break;
-
+	  
 	case ROTATE:
-	  if (arg1 < 0)
-	    return 0;
-
-	  arg1 %= width;
-	  val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
-		 | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
-	  break;
-
-	case COMPARE:
-	  /* Do nothing here.  */
-	  return 0;
-
-	case SMIN:
-	  val = arg0s <= arg1s ? arg0s : arg1s;
-	  break;
-
-	case UMIN:
-	  val = ((unsigned HOST_WIDE_INT) arg0
-		 <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
-	  break;
+	  if (wide_int::from_rtx (op1, mode).neg_p ())
+	    return NULL_RTX;
 
-	case SMAX:
-	  val = arg0s > arg1s ? arg0s : arg1s;
+	  result = wop0.lrotate (op1);
 	  break;
+	  
+	case ROTATERT:
+	  if (wide_int::from_rtx (op1, mode).neg_p ())
+	    return NULL_RTX;
 
-	case UMAX:
-	  val = ((unsigned HOST_WIDE_INT) arg0
-		 > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
+	  result = wop0.rrotate (op1);
 	  break;
 
-	case SS_PLUS:
-	case US_PLUS:
-	case SS_MINUS:
-	case US_MINUS:
-	case SS_MULT:
-	case US_MULT:
-	case SS_DIV:
-	case US_DIV:
-	case SS_ASHIFT:
-	case US_ASHIFT:
-	  /* ??? There are simplifications that can be done.  */
-	  return 0;
-
 	default:
-	  gcc_unreachable ();
+	  return NULL_RTX;
 	}
-
-      return gen_int_mode (val, mode);
+      return immed_wide_int_const (result, mode);
     }
 
   return NULL_RTX;
@@ -4837,10 +4473,11 @@ comparison_result (enum rtx_code code, int known_results)
     }
 }
 
-/* Check if the given comparison (done in the given MODE) is actually a
-   tautology or a contradiction.
-   If no simplification is possible, this function returns zero.
-   Otherwise, it returns either const_true_rtx or const0_rtx.  */
+/* Check if the given comparison (done in the given MODE) is actually
+   a tautology or a contradiction.  If the mode is VOID_mode, the
+   comparison is done in "infinite precision".  If no simplification
+   is possible, this function returns zero.  Otherwise, it returns
+   either const_true_rtx or const0_rtx.  */
 
 rtx
 simplify_const_relational_operation (enum rtx_code code,
@@ -4964,59 +4601,23 @@ simplify_const_relational_operation (enum rtx_code code,
 
   /* Otherwise, see if the operands are both integers.  */
   if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
-       && (CONST_DOUBLE_AS_INT_P (trueop0) || CONST_INT_P (trueop0))
-       && (CONST_DOUBLE_AS_INT_P (trueop1) || CONST_INT_P (trueop1)))
+      && CONST_SCALAR_INT_P (trueop0) && CONST_SCALAR_INT_P (trueop1))
     {
-      int width = GET_MODE_PRECISION (mode);
-      HOST_WIDE_INT l0s, h0s, l1s, h1s;
-      unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
-
-      /* Get the two words comprising each integer constant.  */
-      if (CONST_DOUBLE_AS_INT_P (trueop0))
-	{
-	  l0u = l0s = CONST_DOUBLE_LOW (trueop0);
-	  h0u = h0s = CONST_DOUBLE_HIGH (trueop0);
-	}
-      else
-	{
-	  l0u = l0s = INTVAL (trueop0);
-	  h0u = h0s = HWI_SIGN_EXTEND (l0s);
-	}
-
-      if (CONST_DOUBLE_AS_INT_P (trueop1))
-	{
-	  l1u = l1s = CONST_DOUBLE_LOW (trueop1);
-	  h1u = h1s = CONST_DOUBLE_HIGH (trueop1);
-	}
-      else
-	{
-	  l1u = l1s = INTVAL (trueop1);
-	  h1u = h1s = HWI_SIGN_EXTEND (l1s);
-	}
-
-      /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
-	 we have to sign or zero-extend the values.  */
-      if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
-	{
-	  l0u &= GET_MODE_MASK (mode);
-	  l1u &= GET_MODE_MASK (mode);
-
-	  if (val_signbit_known_set_p (mode, l0s))
-	    l0s |= ~GET_MODE_MASK (mode);
-
-	  if (val_signbit_known_set_p (mode, l1s))
-	    l1s |= ~GET_MODE_MASK (mode);
-	}
-      if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
-	h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
-
-      if (h0u == h1u && l0u == l1u)
+      enum machine_mode cmode = mode;
+      wide_int wo0;
+
+      /* It would be nice if we really had a mode here.  However, the
+	 largest int representable on the target is as good as
+	 infinite.  */
+      if (mode == VOIDmode)
+	cmode = MAX_MODE_INT;
+      wo0 = wide_int::from_rtx (trueop0, cmode);
+      if (wo0 == trueop1)
 	return comparison_result (code, CMP_EQ);
       else
 	{
-	  int cr;
-	  cr = (h0s < h1s || (h0s == h1s && l0u < l1u)) ? CMP_LT : CMP_GT;
-	  cr |= (h0u < h1u || (h0u == h1u && l0u < l1u)) ? CMP_LTU : CMP_GTU;
+	  int cr = wo0.lts_p (trueop1) ? CMP_LT : CMP_GT;
+	  cr |= wo0.ltu_p (trueop1) ? CMP_LTU : CMP_GTU;
 	  return comparison_result (code, cr);
 	}
     }
@@ -5472,9 +5073,9 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
   return 0;
 }
 
-/* Evaluate a SUBREG of a CONST_INT or CONST_DOUBLE or CONST_FIXED
-   or CONST_VECTOR,
-   returning another CONST_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
+/* Evaluate a SUBREG of a CONST_INT or CONST_WIDE_INT or CONST_DOUBLE
+   or CONST_FIXED or CONST_VECTOR, returning another CONST_INT or
+   CONST_WIDE_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
 
    Works by unpacking OP into a collection of 8-bit values
    represented as a little-endian array of 'unsigned char', selecting by BYTE,
@@ -5484,13 +5085,11 @@ static rtx
 simplify_immed_subreg (enum machine_mode outermode, rtx op,
 		       enum machine_mode innermode, unsigned int byte)
 {
-  /* We support up to 512-bit values (for V8DFmode).  */
   enum {
-    max_bitsize = 512,
     value_bit = 8,
     value_mask = (1 << value_bit) - 1
   };
-  unsigned char value[max_bitsize / value_bit];
+  unsigned char value[MAX_BITSIZE_MODE_ANY_MODE/value_bit];
   int value_start;
   int i;
   int elem;
@@ -5502,6 +5101,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
   rtvec result_v = NULL;
   enum mode_class outer_class;
   enum machine_mode outer_submode;
+  int max_bitsize;
 
   /* Some ports misuse CCmode.  */
   if (GET_MODE_CLASS (outermode) == MODE_CC && CONST_INT_P (op))
@@ -5511,6 +5111,10 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
   if (COMPLEX_MODE_P (outermode))
     return NULL_RTX;
 
+  /* We support any size mode.  */
+  max_bitsize = MAX (GET_MODE_BITSIZE (outermode), 
+		     GET_MODE_BITSIZE (innermode));
+
   /* Unpack the value.  */
 
   if (GET_CODE (op) == CONST_VECTOR)
@@ -5560,8 +5164,20 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	    *vp++ = INTVAL (el) < 0 ? -1 : 0;
 	  break;
 
+	case CONST_WIDE_INT:
+	  {
+	    wide_int val = wide_int::from_rtx (el, innermode);
+	    unsigned char extend = val.sign_mask ();
+
+	    for (i = 0; i < elem_bitsize; i += value_bit) 
+	      *vp++ = val.extract_to_hwi (i, value_bit);
+	    for (; i < elem_bitsize; i += value_bit)
+	      *vp++ = extend;
+	  }
+	  break;
+
 	case CONST_DOUBLE:
-	  if (GET_MODE (el) == VOIDmode)
+	  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (el) == VOIDmode)
 	    {
 	      unsigned char extend = 0;
 	      /* If this triggers, someone should have generated a
@@ -5584,7 +5200,8 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	    }
 	  else
 	    {
-	      long tmp[max_bitsize / 32];
+	      /* This is big enough for anything on the platform.  */
+	      long tmp[MAX_BITSIZE_MODE_ANY_MODE / 32];
 	      int bitsize = GET_MODE_BITSIZE (GET_MODE (el));
 
 	      gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (el)));
@@ -5704,24 +5321,27 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	case MODE_INT:
 	case MODE_PARTIAL_INT:
 	  {
-	    unsigned HOST_WIDE_INT hi = 0, lo = 0;
-
-	    for (i = 0;
-		 i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
-		 i += value_bit)
-	      lo |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
-	    for (; i < elem_bitsize; i += value_bit)
-	      hi |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask)
-		     << (i - HOST_BITS_PER_WIDE_INT);
-
-	    /* immed_double_const doesn't call trunc_int_for_mode.  I don't
-	       know why.  */
-	    if (elem_bitsize <= HOST_BITS_PER_WIDE_INT)
-	      elems[elem] = gen_int_mode (lo, outer_submode);
-	    else if (elem_bitsize <= HOST_BITS_PER_DOUBLE_INT)
-	      elems[elem] = immed_double_const (lo, hi, outer_submode);
-	    else
-	      return NULL_RTX;
+	    int u;
+	    int base = 0;
+	    int units 
+	      = (GET_MODE_BITSIZE (outer_submode) + HOST_BITS_PER_WIDE_INT - 1) 
+	      / HOST_BITS_PER_WIDE_INT;
+	    HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+	    wide_int r;
+
+	    for (u = 0; u < units; u++) 
+	      {
+		unsigned HOST_WIDE_INT buf = 0;
+		for (i = 0; 
+		     i < HOST_BITS_PER_WIDE_INT && base + i < elem_bitsize; 
+		     i += value_bit)
+		  buf |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
+
+		tmp[u] = buf;
+		base += HOST_BITS_PER_WIDE_INT;
+	      }
+	    r = wide_int::from_array (tmp, units, outer_submode);
+	    elems[elem] = immed_wide_int_const (r, outer_submode);
 	  }
 	  break;
 
@@ -5729,7 +5349,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	case MODE_DECIMAL_FLOAT:
 	  {
 	    REAL_VALUE_TYPE r;
-	    long tmp[max_bitsize / 32];
+	    long tmp[MAX_BITSIZE_MODE_ANY_INT / 32];
 
 	    /* real_from_target wants its input in words affected by
 	       FLOAT_WORDS_BIG_ENDIAN.  However, we ignore this,
diff --git a/gcc/tree-ssa-address.c b/gcc/tree-ssa-address.c
index cfd42ad..85b1552 100644
--- a/gcc/tree-ssa-address.c
+++ b/gcc/tree-ssa-address.c
@@ -189,15 +189,18 @@ addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
   struct mem_addr_template *templ;
 
   if (addr->step && !integer_onep (addr->step))
-    st = immed_double_int_const (tree_to_double_int (addr->step), pointer_mode);
+    st = immed_wide_int_const (wide_int::from_tree (addr->step),
+			       TYPE_MODE (TREE_TYPE (addr->step)));
   else
     st = NULL_RTX;
 
   if (addr->offset && !integer_zerop (addr->offset))
-    off = immed_double_int_const
-	    (tree_to_double_int (addr->offset)
-	     .sext (TYPE_PRECISION (TREE_TYPE (addr->offset))),
-	     pointer_mode);
+    {
+      wide_int dc = wide_int::from_tree (addr->offset);
+      dc = dc.sforce_to_size (TREE_TYPE (addr->offset));
+      off = immed_wide_int_const (dc,
+			       TYPE_MODE (TREE_TYPE (addr->offset)));
+    }
   else
     off = NULL_RTX;
 
diff --git a/gcc/tree.c b/gcc/tree.c
index d8f2424..f40871a 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -59,6 +59,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "except.h"
 #include "debug.h"
 #include "intl.h"
+#include "wide-int.h"
 
 /* Tree code classes.  */
 
@@ -1067,6 +1068,33 @@ double_int_to_tree (tree type, double_int cst)
   return build_int_cst_wide (type, cst.low, cst.high);
 }
 
+/* Constructs tree in type TYPE from with value given by CST.  Signedness
+   of CST is assumed to be the same as the signedness of TYPE.  */
+
+tree
+wide_int_to_tree (tree type, const wide_int &cst)
+{
+  wide_int v;
+  unsigned int new_prec = TYPE_PRECISION (type);
+  
+  gcc_assert (cst.get_len () <= 2);
+  wide_int::SignOp sgn = TYPE_UNSIGNED (type) ? wide_int::UNSIGNED : wide_int::SIGNED;
+
+  /* This is something of a temporary hack.  The current rep of a
+     INT_CST looks at all of the bits, even those past the precision
+     of the type.  So we have to accomodate this.  The first test
+     checks to see if the type we want to make this is shorter than
+     the current rep, but the second block just goes and extends what
+     is there to the full size of the INT_CST.  */ 
+  if (new_prec < cst.get_precision ())
+    v = cst.zext (TYPE_PRECISION (type))
+      .force_to_size (HOST_BITS_PER_DOUBLE_INT, sgn);
+  else
+    v = cst.force_to_size (HOST_BITS_PER_DOUBLE_INT, sgn);
+
+  return build_int_cst_wide (type, v.elt (0), v.elt (1));
+}
+
 /* Returns true if CST fits into range of TYPE.  Signedness of CST is assumed
    to be the same as the signedness of TYPE.  */
 
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index 4855fb1..5de9d25 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -3513,6 +3513,23 @@ loc_cmp (rtx x, rtx y)
       default:
 	gcc_unreachable ();
       }
+  if (CONST_WIDE_INT_P (x))
+    {
+      /* Compare the vector length first.  */
+      if (CONST_WIDE_INT_NUNITS (x) >= CONST_WIDE_INT_NUNITS (y))
+	return 1;
+      else if (CONST_WIDE_INT_NUNITS (x) < CONST_WIDE_INT_NUNITS (y))
+	return -1;
+
+      /* Compare the vectors elements.  */;
+      for (j = CONST_WIDE_INT_NUNITS (x) - 1; j >= 0 ; j--)
+	{
+	  if (CONST_WIDE_INT_ELT (x, j) < CONST_WIDE_INT_ELT (y, j))
+	    return -1;
+	  if (CONST_WIDE_INT_ELT (x, j) > CONST_WIDE_INT_ELT (y, j))
+	    return 1;
+	}
+    }
 
   return 0;
 }
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 2532d80..7cca674 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -3406,6 +3406,7 @@ const_rtx_hash_1 (rtx *xp, void *data)
   enum rtx_code code;
   hashval_t h, *hp;
   rtx x;
+  int i;
 
   x = *xp;
   code = GET_CODE (x);
@@ -3416,12 +3417,12 @@ const_rtx_hash_1 (rtx *xp, void *data)
     {
     case CONST_INT:
       hwi = INTVAL (x);
+
     fold_hwi:
       {
 	int shift = sizeof (hashval_t) * CHAR_BIT;
 	const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t);
-	int i;
-
+	
 	h ^= (hashval_t) hwi;
 	for (i = 1; i < n; ++i)
 	  {
@@ -3431,8 +3432,16 @@ const_rtx_hash_1 (rtx *xp, void *data)
       }
       break;
 
+    case CONST_WIDE_INT:
+      hwi = GET_MODE_PRECISION (mode);
+      {
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hwi ^= CONST_WIDE_INT_ELT (x, i);
+	goto fold_hwi;
+      }
+
     case CONST_DOUBLE:
-      if (mode == VOIDmode)
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && mode == VOIDmode)
 	{
 	  hwi = CONST_DOUBLE_LOW (x) ^ CONST_DOUBLE_HIGH (x);
 	  goto fold_hwi;

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - builtins.c - the first of the tree level patches for wide-int
  2013-04-17  0:49                                                                                 ` Kenneth Zadeck
  2013-04-17  3:41                                                                                   ` patch to fix constant math -5th patch, rtl Kenneth Zadeck
@ 2013-04-17  7:34                                                                                   ` Kenneth Zadeck
  2013-05-02 17:53                                                                                     ` Kenneth Zadeck
  2013-04-17 15:01                                                                                   ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Kenneth Zadeck
  2013-04-19 15:35                                                                                   ` Richard Biener
  3 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-17  7:34 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 866 bytes --]

Richard, this is the first of the tree level patches so that you can see 
how the wide-int changes will effect the tree level.   This patch 
converts builtins.c so that it does not in any way assume that tree-cst 
holds two HWIs.   The patch divides all math into two categories:   
Things that are always so small that we can easily assume that the math 
can be done using a single HWI and everything else.   The things that it 
assumes can easily be done with a HWI are guarded with assertions.   The 
everything else is done with wide-int.  Everything else in this patch is 
additional abi to support this.

The idea is that each pass will be converted, 1 pass per patch in this 
way.    Once everything does not depend on the internals of tree-cst as 
they do now, then tree-cst will be converted to have an array inside of 
it rather than just two hwis.

Kenny

[-- Attachment #2: t1-1.clog --]
[-- Type: text/plain, Size: 1316 bytes --]

2012-04-16  Kenneth Zadeck <zadeck@naturalbridge.com>

	* builtins.c (get_object_alignment_2, get_pointer_alignment_1,
	c_strlen, c_getstr, target_char_cast,
	expand_builtin_mempcpy_args, expand_builtin_strncpy,
	expand_builtin_memset_args, expand_builtin_strncpy,
	expand_builtin_memset_args, expand_builtin_frame_address,
	expand_builtin_alloca, expand_builtin_atomic_compare_exchange,
	fold_builtin_powi, fold_builtin_memset,
	fold_builtin_memory_op, fold_builtin_memchr,
	fold_builtin_memcmp, fold_builtin_strncmp,
	fold_builtin_load_exponent, fold_builtin_snprintf,
	expand_builtin_object_size, expand_builtin_memory_chk,
	maybe_emit_chk_warning, maybe_emit_sprintf_chk_warning,
	fold_builtin_object_size, fold_builtin_memory_chk,
	fold_builtin_stxcpy_chk, fold_builtin_strcat_chk,
	fold_builtin_sprintf_chk_1, fold_builtin_snprintf_chk_1,
	do_mpfr_bessel_n): Convert to api that does not assume that
	tree_cst is two HWIs.
	(fold_builtin_int_roundingfn, fold_builtin_bitop,
	fold_builtin_bswap, fold_builtin_memory_op,
	expand_builtin_object_size): Use wide-int rather than double-int api.
	
	* dfp.c (decimal_real_to_integer): Add wide-int version. 
	* real.c (real_to_integer): Ditto.
	* tree.h (tree_fits_uhwi_p, tree_fits_shwi_p, tree_fits_hwi_p, 
	tree_to_shwi, tree_to_hwi, tree_to_uhwi): New functions.

[-- Attachment #3: t1-1.diff --]
[-- Type: text/x-patch, Size: 39534 bytes --]

diff --git a/gcc/builtins.c b/gcc/builtins.c
index ed5a6b3..5ba2297 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -339,8 +339,8 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
       if (TREE_CODE (addr) == BIT_AND_EXPR
 	  && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
 	{
-	  align = (TREE_INT_CST_LOW (TREE_OPERAND (addr, 1))
-		    & -TREE_INT_CST_LOW (TREE_OPERAND (addr, 1)));
+	  align = (tree_to_hwi (TREE_OPERAND (addr, 1))
+		   & -tree_to_hwi (TREE_OPERAND (addr, 1)));
 	  align *= BITS_PER_UNIT;
 	  addr = TREE_OPERAND (addr, 0);
 	}
@@ -357,7 +357,7 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
 	    {
 	      unsigned HOST_WIDE_INT step = 1;
 	      if (TMR_STEP (exp))
-		step = TREE_INT_CST_LOW (TMR_STEP (exp));
+		step = tree_to_hwi (TMR_STEP (exp));
 	      align = MIN (align, (step & -step) * BITS_PER_UNIT);
 	    }
 	  if (TMR_INDEX2 (exp))
@@ -379,7 +379,8 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
 	  bitpos += ptr_bitpos;
 	  if (TREE_CODE (exp) == MEM_REF
 	      || TREE_CODE (exp) == TARGET_MEM_REF)
-	    bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT;
+	    bitpos += wide_int::from_tree (TREE_OPERAND (exp, 1))
+	      .to_shwi () * BITS_PER_UNIT;
 	}
     }
   else if (TREE_CODE (exp) == STRING_CST)
@@ -408,23 +409,23 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
 	}
       else
 	next_offset = NULL;
-      if (host_integerp (offset, 1))
+      if (tree_fits_uhwi_p (offset))
 	{
 	  /* Any overflow in calculating offset_bits won't change
 	     the alignment.  */
 	  unsigned offset_bits
-	    = ((unsigned) tree_low_cst (offset, 1) * BITS_PER_UNIT);
+	    = ((unsigned) tree_to_hwi (offset) * BITS_PER_UNIT);
 
 	  if (offset_bits)
 	    inner = MIN (inner, (offset_bits & -offset_bits));
 	}
       else if (TREE_CODE (offset) == MULT_EXPR
-	       && host_integerp (TREE_OPERAND (offset, 1), 1))
+	       && tree_fits_uhwi_p (TREE_OPERAND (offset, 1)))
 	{
 	  /* Any overflow in calculating offset_factor won't change
 	     the alignment.  */
 	  unsigned offset_factor
-	    = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
+	    = ((unsigned) tree_to_hwi (TREE_OPERAND (offset, 1))
 	       * BITS_PER_UNIT);
 
 	  if (offset_factor)
@@ -515,7 +516,7 @@ get_pointer_alignment_1 (tree exp, unsigned int *alignp,
   else if (TREE_CODE (exp) == INTEGER_CST)
     {
       *alignp = BIGGEST_ALIGNMENT;
-      *bitposp = ((TREE_INT_CST_LOW (exp) * BITS_PER_UNIT)
+      *bitposp = ((tree_to_hwi (exp) * BITS_PER_UNIT)
 		  & (BIGGEST_ALIGNMENT - 1));
       return true;
     }
@@ -624,10 +625,10 @@ c_strlen (tree src, int only_value)
      a null character if we can represent it as a single HOST_WIDE_INT.  */
   if (offset_node == 0)
     offset = 0;
-  else if (! host_integerp (offset_node, 0))
+  else if (!tree_fits_shwi_p (offset_node))
     offset = -1;
   else
-    offset = tree_low_cst (offset_node, 0);
+    offset = tree_to_hwi (offset_node);
 
   /* If the offset is known to be out of bounds, warn, and call strlen at
      runtime.  */
@@ -665,11 +666,11 @@ c_getstr (tree src)
 
   if (offset_node == 0)
     return TREE_STRING_POINTER (src);
-  else if (!host_integerp (offset_node, 1)
+  else if (!tree_fits_uhwi_p (offset_node)
 	   || compare_tree_int (offset_node, TREE_STRING_LENGTH (src) - 1) > 0)
     return 0;
 
-  return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
+  return TREE_STRING_POINTER (src) + tree_to_uhwi (offset_node);
 }
 
 /* Return a constant integer corresponding to target reading
@@ -723,7 +724,9 @@ target_char_cast (tree cst, char *p)
       || CHAR_TYPE_SIZE > HOST_BITS_PER_WIDE_INT)
     return 1;
 
-  val = TREE_INT_CST_LOW (cst);
+  /* Do not care if it fits or not right here.  */
+  val = tree_to_hwi (cst);
+
   if (CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT)
     val &= (((unsigned HOST_WIDE_INT) 1) << CHAR_TYPE_SIZE) - 1;
 
@@ -3168,7 +3171,7 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len,
 	return NULL_RTX;
 
       /* If LEN is not constant, call the normal function.  */
-      if (! host_integerp (len, 1))
+      if (! tree_fits_uhwi_p (len))
 	return NULL_RTX;
 
       len_rtx = expand_normal (len);
@@ -3403,7 +3406,7 @@ expand_builtin_strncpy (tree exp, rtx target)
       tree slen = c_strlen (src, 1);
 
       /* We must be passed a constant len and src parameter.  */
-      if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1))
+      if (!tree_fits_uhwi_p (len) || !slen || !tree_fits_uhwi_p (slen))
 	return NULL_RTX;
 
       slen = size_binop_loc (loc, PLUS_EXPR, slen, ssize_int (1));
@@ -3417,15 +3420,15 @@ expand_builtin_strncpy (tree exp, rtx target)
 	  const char *p = c_getstr (src);
 	  rtx dest_mem;
 
-	  if (!p || dest_align == 0 || !host_integerp (len, 1)
-	      || !can_store_by_pieces (tree_low_cst (len, 1),
+	  if (!p || dest_align == 0 || !tree_fits_uhwi_p (len)
+	      || !can_store_by_pieces (tree_to_uhwi (len),
 				       builtin_strncpy_read_str,
 				       CONST_CAST (char *, p),
 				       dest_align, false))
 	    return NULL_RTX;
 
 	  dest_mem = get_memory_rtx (dest, len);
-	  store_by_pieces (dest_mem, tree_low_cst (len, 1),
+	  store_by_pieces (dest_mem, tree_to_uhwi (len),
 			   builtin_strncpy_read_str,
 			   CONST_CAST (char *, p), dest_align, false, 0);
 	  dest_mem = force_operand (XEXP (dest_mem, 0), target);
@@ -3558,13 +3561,13 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
        * the coefficients by pieces (in the required modes).
        * We can't pass builtin_memset_gen_str as that emits RTL.  */
       c = 1;
-      if (host_integerp (len, 1)
-	  && can_store_by_pieces (tree_low_cst (len, 1),
+      if (tree_fits_uhwi_p (len)
+	  && can_store_by_pieces (tree_to_hwi (len),
 				  builtin_memset_read_str, &c, dest_align,
 				  true))
 	{
 	  val_rtx = force_reg (val_mode, val_rtx);
-	  store_by_pieces (dest_mem, tree_low_cst (len, 1),
+	  store_by_pieces (dest_mem, tree_to_hwi (len),
 			   builtin_memset_gen_str, val_rtx, dest_align,
 			   true, 0);
 	}
@@ -3583,11 +3586,11 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
 
   if (c)
     {
-      if (host_integerp (len, 1)
-	  && can_store_by_pieces (tree_low_cst (len, 1),
+      if (tree_fits_uhwi_p (len)
+	  && can_store_by_pieces (tree_to_hwi (len),
 				  builtin_memset_read_str, &c, dest_align,
 				  true))
-	store_by_pieces (dest_mem, tree_low_cst (len, 1),
+	store_by_pieces (dest_mem, tree_to_hwi (len),
 			 builtin_memset_read_str, &c, dest_align, true, 0);
       else if (!set_storage_via_setmem (dest_mem, len_rtx,
 					gen_int_mode (c, val_mode),
@@ -4492,7 +4495,7 @@ expand_builtin_frame_address (tree fndecl, tree exp)
   if (call_expr_nargs (exp) == 0)
     /* Warning about missing arg was already issued.  */
     return const0_rtx;
-  else if (! host_integerp (CALL_EXPR_ARG (exp, 0), 1))
+  else if (! tree_fits_uhwi_p (CALL_EXPR_ARG (exp, 0)))
     {
       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
 	error ("invalid argument to %<__builtin_frame_address%>");
@@ -4504,7 +4507,7 @@ expand_builtin_frame_address (tree fndecl, tree exp)
     {
       rtx tem
 	= expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl),
-				      tree_low_cst (CALL_EXPR_ARG (exp, 0), 1));
+				      tree_to_uhwi (CALL_EXPR_ARG (exp, 0)));
 
       /* Some ports cannot access arbitrary stack frames.  */
       if (tem == NULL)
@@ -4558,7 +4561,7 @@ expand_builtin_alloca (tree exp, bool cannot_accumulate)
 
   /* Compute the alignment.  */
   align = (alloca_with_align
-	   ? TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 1))
+	   ? tree_to_uhwi (CALL_EXPR_ARG (exp, 1))
 	   : BIGGEST_ALIGNMENT);
 
   /* Allocate the desired space.  */
@@ -5390,7 +5393,7 @@ expand_builtin_atomic_compare_exchange (enum machine_mode mode, tree exp,
 
   weak = CALL_EXPR_ARG (exp, 3);
   is_weak = false;
-  if (host_integerp (weak, 0) && tree_low_cst (weak, 0) != 0)
+  if (tree_fits_shwi_p (weak) && tree_to_hwi (weak) != 0)
     is_weak = true;
 
   oldval = expect;
@@ -8026,8 +8029,9 @@ fold_builtin_int_roundingfn (location_t loc, tree fndecl, tree arg)
 	{
 	  tree itype = TREE_TYPE (TREE_TYPE (fndecl));
 	  tree ftype = TREE_TYPE (arg);
-	  double_int val;
+	  wide_int val;
 	  REAL_VALUE_TYPE r;
+	  bool fail = false;
 
 	  switch (DECL_FUNCTION_CODE (fndecl))
 	    {
@@ -8053,9 +8057,10 @@ fold_builtin_int_roundingfn (location_t loc, tree fndecl, tree arg)
 	      gcc_unreachable ();
 	    }
 
-	  real_to_integer2 ((HOST_WIDE_INT *)&val.low, &val.high, &r);
-	  if (double_int_fits_to_tree_p (itype, val))
-	    return double_int_to_tree (itype, val);
+	  val = real_to_integer (&r, &fail, 
+				 TYPE_PRECISION (itype));
+	  if (!fail)
+	    return wide_int_to_tree (itype, val);
 	}
     }
 
@@ -8088,100 +8093,40 @@ fold_builtin_bitop (tree fndecl, tree arg)
   /* Optimize for constant argument.  */
   if (TREE_CODE (arg) == INTEGER_CST && !TREE_OVERFLOW (arg))
     {
-      HOST_WIDE_INT hi, width, result;
-      unsigned HOST_WIDE_INT lo;
-      tree type;
-
-      type = TREE_TYPE (arg);
-      width = TYPE_PRECISION (type);
-      lo = TREE_INT_CST_LOW (arg);
-
-      /* Clear all the bits that are beyond the type's precision.  */
-      if (width > HOST_BITS_PER_WIDE_INT)
-	{
-	  hi = TREE_INT_CST_HIGH (arg);
-	  if (width < HOST_BITS_PER_DOUBLE_INT)
-	    hi &= ~((unsigned HOST_WIDE_INT) (-1)
-		    << (width - HOST_BITS_PER_WIDE_INT));
-	}
-      else
-	{
-	  hi = 0;
-	  if (width < HOST_BITS_PER_WIDE_INT)
-	    lo &= ~((unsigned HOST_WIDE_INT) (-1) << width);
-	}
+      wide_int warg = wide_int::from_tree (arg);
+      wide_int result;
 
       switch (DECL_FUNCTION_CODE (fndecl))
 	{
 	CASE_INT_FN (BUILT_IN_FFS):
-	  if (lo != 0)
-	    result = ffs_hwi (lo);
-	  else if (hi != 0)
-	    result = HOST_BITS_PER_WIDE_INT + ffs_hwi (hi);
-	  else
-	    result = 0;
+	  result = warg.ffs ();
 	  break;
 
 	CASE_INT_FN (BUILT_IN_CLZ):
-	  if (hi != 0)
-	    result = width - floor_log2 (hi) - 1 - HOST_BITS_PER_WIDE_INT;
-	  else if (lo != 0)
-	    result = width - floor_log2 (lo) - 1;
-	  else if (! CLZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (type), result))
-	    result = width;
+	  result = warg.clz ();
 	  break;
 
 	CASE_INT_FN (BUILT_IN_CTZ):
-	  if (lo != 0)
-	    result = ctz_hwi (lo);
-	  else if (hi != 0)
-	    result = HOST_BITS_PER_WIDE_INT + ctz_hwi (hi);
-	  else if (! CTZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (type), result))
-	    result = width;
+	  result = warg.ctz ();
 	  break;
 
 	CASE_INT_FN (BUILT_IN_CLRSB):
-	  if (width > HOST_BITS_PER_WIDE_INT
-	      && (hi & ((unsigned HOST_WIDE_INT) 1
-			<< (width - HOST_BITS_PER_WIDE_INT - 1))) != 0)
-	    {
-	      hi = ~hi & ~((unsigned HOST_WIDE_INT) (-1)
-			   << (width - HOST_BITS_PER_WIDE_INT - 1));
-	      lo = ~lo;
-	    }
-	  else if (width <= HOST_BITS_PER_WIDE_INT
-		   && (lo & ((unsigned HOST_WIDE_INT) 1 << (width - 1))) != 0)
-	    lo = ~lo & ~((unsigned HOST_WIDE_INT) (-1) << (width - 1));
-	  if (hi != 0)
-	    result = width - floor_log2 (hi) - 2 - HOST_BITS_PER_WIDE_INT;
-	  else if (lo != 0)
-	    result = width - floor_log2 (lo) - 2;
-	  else
-	    result = width - 1;
+	  result = warg.clrsb ();
 	  break;
 
 	CASE_INT_FN (BUILT_IN_POPCOUNT):
-	  result = 0;
-	  while (lo)
-	    result++, lo &= lo - 1;
-	  while (hi)
-	    result++, hi &= (unsigned HOST_WIDE_INT) hi - 1;
+	  result = warg.popcount ();
 	  break;
 
 	CASE_INT_FN (BUILT_IN_PARITY):
-	  result = 0;
-	  while (lo)
-	    result++, lo &= lo - 1;
-	  while (hi)
-	    result++, hi &= (unsigned HOST_WIDE_INT) hi - 1;
-	  result &= 1;
+	  result = warg.parity ();
 	  break;
 
 	default:
 	  gcc_unreachable ();
 	}
 
-      return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), result);
+      return wide_int_to_tree (TREE_TYPE (TREE_TYPE (fndecl)), result);
     }
 
   return NULL_TREE;
@@ -8198,49 +8143,21 @@ fold_builtin_bswap (tree fndecl, tree arg)
   /* Optimize constant value.  */
   if (TREE_CODE (arg) == INTEGER_CST && !TREE_OVERFLOW (arg))
     {
-      HOST_WIDE_INT hi, width, r_hi = 0;
-      unsigned HOST_WIDE_INT lo, r_lo = 0;
       tree type = TREE_TYPE (TREE_TYPE (fndecl));
 
-      width = TYPE_PRECISION (type);
-      lo = TREE_INT_CST_LOW (arg);
-      hi = TREE_INT_CST_HIGH (arg);
-
       switch (DECL_FUNCTION_CODE (fndecl))
 	{
 	  case BUILT_IN_BSWAP16:
 	  case BUILT_IN_BSWAP32:
 	  case BUILT_IN_BSWAP64:
 	    {
-	      int s;
-
-	      for (s = 0; s < width; s += 8)
-		{
-		  int d = width - s - 8;
-		  unsigned HOST_WIDE_INT byte;
-
-		  if (s < HOST_BITS_PER_WIDE_INT)
-		    byte = (lo >> s) & 0xff;
-		  else
-		    byte = (hi >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff;
-
-		  if (d < HOST_BITS_PER_WIDE_INT)
-		    r_lo |= byte << d;
-		  else
-		    r_hi |= byte << (d - HOST_BITS_PER_WIDE_INT);
-		}
+	      tree result = wide_int_to_tree (type, wide_int::from_tree (arg)
+					      .force_to_size (type).bswap ());
+	      return result;
 	    }
-
-	    break;
-
 	default:
 	  gcc_unreachable ();
 	}
-
-      if (width < HOST_BITS_PER_WIDE_INT)
-	return build_int_cst (type, r_lo);
-      else
-	return build_int_cst_wide (type, r_lo, r_hi);
     }
 
   return NULL_TREE;
@@ -8553,9 +8470,9 @@ fold_builtin_powi (location_t loc, tree fndecl ATTRIBUTE_UNUSED,
   if (real_onep (arg0))
     return omit_one_operand_loc (loc, type, build_real (type, dconst1), arg1);
 
-  if (host_integerp (arg1, 0))
+  if (tree_fits_shwi_p (arg1))
     {
-      HOST_WIDE_INT c = TREE_INT_CST_LOW (arg1);
+      HOST_WIDE_INT c = tree_to_hwi (arg1);
 
       /* Evaluate powi at compile-time.  */
       if (TREE_CODE (arg0) == REAL_CST
@@ -8652,7 +8569,7 @@ fold_builtin_memset (location_t loc, tree dest, tree c, tree len,
       || ! validate_arg (len, INTEGER_TYPE))
     return NULL_TREE;
 
-  if (! host_integerp (len, 1))
+  if (! tree_fits_uhwi_p (len))
     return NULL_TREE;
 
   /* If the LEN parameter is zero, return DEST.  */
@@ -8682,7 +8599,7 @@ fold_builtin_memset (location_t loc, tree dest, tree c, tree len,
   if (! var_decl_component_p (var))
     return NULL_TREE;
 
-  length = tree_low_cst (len, 1);
+  length = tree_to_uhwi (len);
   if (GET_MODE_SIZE (TYPE_MODE (etype)) != length
       || get_pointer_alignment (dest) / BITS_PER_UNIT < length)
     return NULL_TREE;
@@ -8697,7 +8614,7 @@ fold_builtin_memset (location_t loc, tree dest, tree c, tree len,
       if (CHAR_BIT != 8 || BITS_PER_UNIT != 8 || HOST_BITS_PER_WIDE_INT > 64)
 	return NULL_TREE;
 
-      cval = TREE_INT_CST_LOW (c);
+      cval = tree_to_hwi (c);
       cval &= 0xff;
       cval |= cval << 8;
       cval |= cval << 16;
@@ -8785,9 +8702,9 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
 	  if (!dest_align || !src_align)
 	    return NULL_TREE;
 	  if (readonly_data_expr (src)
-	      || (host_integerp (len, 1)
+	      || (tree_fits_uhwi_p (len)
 		  && (MIN (src_align, dest_align) / BITS_PER_UNIT
-		      >= (unsigned HOST_WIDE_INT) tree_low_cst (len, 1))))
+		      >= (unsigned HOST_WIDE_INT) tree_to_uhwi (len))))
 	    {
 	      tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
 	      if (!fn)
@@ -8810,8 +8727,8 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
 	      destvar = TREE_OPERAND (dest, 0);
 	      dest_base = get_ref_base_and_extent (destvar, &dest_offset,
 						   &size, &maxsize);
-	      if (host_integerp (len, 1))
-		maxsize = tree_low_cst (len, 1);
+	      if (tree_fits_uhwi_p (len))
+		maxsize = tree_to_hwi (len);
 	      else
 		maxsize = -1;
 	      src_offset /= BITS_PER_UNIT;
@@ -8827,20 +8744,19 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
 	      else if (TREE_CODE (src_base) == MEM_REF
 		       && TREE_CODE (dest_base) == MEM_REF)
 		{
-		  double_int off;
+		  wide_int off;
 		  if (! operand_equal_p (TREE_OPERAND (src_base, 0),
 					 TREE_OPERAND (dest_base, 0), 0))
 		    return NULL_TREE;
-		  off = mem_ref_offset (src_base) +
-					double_int::from_shwi (src_offset);
-		  if (!off.fits_shwi ())
+		  off = wide_int::from_tree (TREE_OPERAND (src_base, 1)) + src_offset;
+		  if (!off.fits_shwi_p ())
 		    return NULL_TREE;
-		  src_offset = off.low;
-		  off = mem_ref_offset (dest_base) +
-					double_int::from_shwi (dest_offset);
-		  if (!off.fits_shwi ())
+		  src_offset = off.to_shwi ();
+
+		  off = wide_int::from_tree (TREE_OPERAND (dest_base, 1)) + dest_offset;
+		  if (!off.fits_shwi_p ())
 		    return NULL_TREE;
-		  dest_offset = off.low;
+		  dest_offset = off.to_shwi ();
 		  if (ranges_overlap_p (src_offset, maxsize,
 					dest_offset, maxsize))
 		    return NULL_TREE;
@@ -8877,7 +8793,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
 	  return NULL_TREE;
 	}
 
-      if (!host_integerp (len, 0))
+      if (!tree_fits_shwi_p (len))
 	return NULL_TREE;
       /* FIXME:
          This logic lose for arguments like (type *)malloc (sizeof (type)),
@@ -9165,7 +9081,7 @@ fold_builtin_memchr (location_t loc, tree arg1, tree arg2, tree len, tree type)
       const char *p1;
 
       if (TREE_CODE (arg2) != INTEGER_CST
-	  || !host_integerp (len, 1))
+	  || !tree_fits_uhwi_p (len))
 	return NULL_TREE;
 
       p1 = c_getstr (arg1);
@@ -9178,7 +9094,7 @@ fold_builtin_memchr (location_t loc, tree arg1, tree arg2, tree len, tree type)
 	  if (target_char_cast (arg2, &c))
 	    return NULL_TREE;
 
-	  r = (const char *) memchr (p1, c, tree_low_cst (len, 1));
+	  r = (const char *) memchr (p1, c, tree_to_uhwi (len));
 
 	  if (r == NULL)
 	    return build_int_cst (TREE_TYPE (arg1), 0);
@@ -9217,11 +9133,11 @@ fold_builtin_memcmp (location_t loc, tree arg1, tree arg2, tree len)
 
   /* If all arguments are constant, and the value of len is not greater
      than the lengths of arg1 and arg2, evaluate at compile-time.  */
-  if (host_integerp (len, 1) && p1 && p2
+  if (tree_fits_uhwi_p (len) && p1 && p2
       && compare_tree_int (len, strlen (p1) + 1) <= 0
       && compare_tree_int (len, strlen (p2) + 1) <= 0)
     {
-      const int r = memcmp (p1, p2, tree_low_cst (len, 1));
+      const int r = memcmp (p1, p2, tree_to_uhwi (len));
 
       if (r > 0)
 	return integer_one_node;
@@ -9233,7 +9149,7 @@ fold_builtin_memcmp (location_t loc, tree arg1, tree arg2, tree len)
 
   /* If len parameter is one, return an expression corresponding to
      (*(const unsigned char*)arg1 - (const unsigned char*)arg2).  */
-  if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
+  if (tree_fits_uhwi_p (len) && tree_to_hwi (len) == 1)
     {
       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
       tree cst_uchar_ptr_node
@@ -9345,9 +9261,9 @@ fold_builtin_strncmp (location_t loc, tree arg1, tree arg2, tree len)
   p1 = c_getstr (arg1);
   p2 = c_getstr (arg2);
 
-  if (host_integerp (len, 1) && p1 && p2)
+  if (tree_fits_uhwi_p (len) && p1 && p2)
     {
-      const int i = strncmp (p1, p2, tree_low_cst (len, 1));
+      const int i = strncmp (p1, p2, tree_to_hwi (len));
       if (i > 0)
 	return integer_one_node;
       else if (i < 0)
@@ -9393,7 +9309,7 @@ fold_builtin_strncmp (location_t loc, tree arg1, tree arg2, tree len)
 
   /* If len parameter is one, return an expression corresponding to
      (*(const unsigned char*)arg1 - (const unsigned char*)arg2).  */
-  if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
+  if (tree_fits_uhwi_p (len) && tree_to_hwi (len) == 1)
     {
       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
       tree cst_uchar_ptr_node
@@ -9842,7 +9758,7 @@ fold_builtin_load_exponent (location_t loc, tree arg0, tree arg1,
       /* If both arguments are constant, then try to evaluate it.  */
       if ((ldexp || REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2)
 	  && TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)
-	  && host_integerp (arg1, 0))
+	  && tree_fits_shwi_p (arg1))
         {
 	  /* Bound the maximum adjustment to twice the range of the
 	     mode's valid exponents.  Use abs to ensure the range is
@@ -9852,7 +9768,7 @@ fold_builtin_load_exponent (location_t loc, tree arg0, tree arg1,
 		 - REAL_MODE_FORMAT (TYPE_MODE (type))->emin);
 
 	  /* Get the user-requested adjustment.  */
-	  const HOST_WIDE_INT req_exp_adj = tree_low_cst (arg1, 0);
+	  const HOST_WIDE_INT req_exp_adj = tree_to_shwi (arg1);
 
 	  /* The requested adjustment must be inside this range.  This
 	     is a preliminary cap to avoid things like overflow, we
@@ -12322,7 +12238,7 @@ fold_builtin_snprintf (location_t loc, tree dest, tree destsize, tree fmt,
   if (orig && !validate_arg (orig, POINTER_TYPE))
     return NULL_TREE;
 
-  if (!host_integerp (destsize, 1))
+  if (!tree_fits_uhwi_p (destsize))
     return NULL_TREE;
 
   /* Check whether the format is a literal string constant.  */
@@ -12336,7 +12252,7 @@ fold_builtin_snprintf (location_t loc, tree dest, tree destsize, tree fmt,
   if (!init_target_chars ())
     return NULL_TREE;
 
-  destlen = tree_low_cst (destsize, 1);
+  destlen = tree_to_hwi (destsize);
 
   /* If the format doesn't contain % args or %%, use strcpy.  */
   if (strchr (fmt_str, target_percent) == NULL)
@@ -12381,10 +12297,10 @@ fold_builtin_snprintf (location_t loc, tree dest, tree destsize, tree fmt,
 	return NULL_TREE;
 
       retval = c_strlen (orig, 1);
-      if (!retval || !host_integerp (retval, 1))  
+      if (!retval || !tree_fits_uhwi_p (retval))  
 	return NULL_TREE;
 
-      origlen = tree_low_cst (retval, 1);
+      origlen = tree_to_hwi (retval);
       /* We could expand this as
 	 memcpy (str1, str2, cst - 1); str1[cst - 1] = '\0';
 	 or to
@@ -12446,7 +12362,7 @@ expand_builtin_object_size (tree exp)
       return const0_rtx;
     }
 
-  object_size_type = tree_low_cst (ost, 0);
+  object_size_type = tree_to_shwi (ost);
 
   return object_size_type < 2 ? constm1_rtx : const0_rtx;
 }
@@ -12475,10 +12391,10 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
   len = CALL_EXPR_ARG (exp, 2);
   size = CALL_EXPR_ARG (exp, 3);
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_RTX;
 
-  if (host_integerp (len, 1) || integer_all_onesp (size))
+  if (tree_fits_uhwi_p (len) || integer_all_onesp (size))
     {
       tree fn;
 
@@ -12609,22 +12525,22 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
   if (!len || !size)
     return;
 
-  if (! host_integerp (size, 1) || integer_all_onesp (size))
+  if (! tree_fits_uhwi_p (size) || integer_all_onesp (size))
     return;
 
   if (is_strlen)
     {
       len = c_strlen (len, 1);
-      if (! len || ! host_integerp (len, 1) || tree_int_cst_lt (len, size))
+      if (! len || ! tree_fits_uhwi_p (len) || tree_int_cst_lt (len, size))
 	return;
     }
   else if (fcode == BUILT_IN_STRNCAT_CHK)
     {
       tree src = CALL_EXPR_ARG (exp, 1);
-      if (! src || ! host_integerp (len, 1) || tree_int_cst_lt (len, size))
+      if (! src || ! tree_fits_uhwi_p (len) || tree_int_cst_lt (len, size))
 	return;
       src = c_strlen (src, 1);
-      if (! src || ! host_integerp (src, 1))
+      if (! src || ! tree_fits_uhwi_p (src))
 	{
 	  warning_at (loc, 0, "%Kcall to %D might overflow destination buffer",
 		      exp, get_callee_fndecl (exp));
@@ -12633,7 +12549,7 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
       else if (tree_int_cst_lt (src, size))
 	return;
     }
-  else if (! host_integerp (len, 1) || ! tree_int_cst_lt (size, len))
+  else if (! tree_fits_uhwi_p (len) || ! tree_int_cst_lt (size, len))
     return;
 
   warning_at (loc, 0, "%Kcall to %D will always overflow destination buffer",
@@ -12657,7 +12573,7 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
   size = CALL_EXPR_ARG (exp, 2);
   fmt = CALL_EXPR_ARG (exp, 3);
 
-  if (! host_integerp (size, 1) || integer_all_onesp (size))
+  if (! tree_fits_uhwi_p (size) || integer_all_onesp (size))
     return;
 
   /* Check whether the format is a literal string constant.  */
@@ -12685,7 +12601,7 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
 	return;
 
       len = c_strlen (arg, 1);
-      if (!len || ! host_integerp (len, 1))
+      if (!len || ! tree_fits_uhwi_p (len))
 	return;
     }
   else
@@ -12728,6 +12644,7 @@ fold_builtin_object_size (tree ptr, tree ost)
 {
   unsigned HOST_WIDE_INT bytes;
   int object_size_type;
+  int precision = TYPE_PRECISION (TREE_TYPE (ptr));
 
   if (!validate_arg (ptr, POINTER_TYPE)
       || !validate_arg (ost, INTEGER_TYPE))
@@ -12740,7 +12657,7 @@ fold_builtin_object_size (tree ptr, tree ost)
       || compare_tree_int (ost, 3) > 0)
     return NULL_TREE;
 
-  object_size_type = tree_low_cst (ost, 0);
+  object_size_type = tree_to_shwi (ost);
 
   /* __builtin_object_size doesn't evaluate side-effects in its arguments;
      if there are any side-effects, it returns (size_t) -1 for types 0 and 1
@@ -12750,21 +12667,24 @@ fold_builtin_object_size (tree ptr, tree ost)
 
   if (TREE_CODE (ptr) == ADDR_EXPR)
     {
-      bytes = compute_builtin_object_size (ptr, object_size_type);
-      if (double_int_fits_to_tree_p (size_type_node,
-				     double_int::from_uhwi (bytes)))
-	return build_int_cstu (size_type_node, bytes);
+
+      wide_int wbytes 
+	= wide_int::from_uhwi (compute_builtin_object_size (ptr, object_size_type),
+			       precision);
+      if (wbytes.fits_to_tree_p (size_type_node))
+	return wide_int_to_tree (size_type_node, wbytes);
     }
   else if (TREE_CODE (ptr) == SSA_NAME)
     {
       /* If object size is not known yet, delay folding until
        later.  Maybe subsequent passes will help determining
        it.  */
+      wide_int wbytes;
       bytes = compute_builtin_object_size (ptr, object_size_type);
+      wbytes = wide_int::from_uhwi (bytes, precision);
       if (bytes != (unsigned HOST_WIDE_INT) (object_size_type < 2 ? -1 : 0)
-          && double_int_fits_to_tree_p (size_type_node,
-					double_int::from_uhwi (bytes)))
-	return build_int_cstu (size_type_node, bytes);
+          && wbytes.fits_to_tree_p (size_type_node))
+	return wide_int_to_tree (size_type_node, wbytes);
     }
 
   return NULL_TREE;
@@ -12806,17 +12726,17 @@ fold_builtin_memory_chk (location_t loc, tree fndecl,
 	}
     }
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_TREE;
 
   if (! integer_all_onesp (size))
     {
-      if (! host_integerp (len, 1))
+      if (! tree_fits_uhwi_p (len))
 	{
 	  /* If LEN is not constant, try MAXLEN too.
 	     For MAXLEN only allow optimizing into non-_ocs function
 	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
-	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
+	  if (maxlen == NULL_TREE || ! tree_fits_uhwi_p (maxlen))
 	    {
 	      if (fcode == BUILT_IN_MEMPCPY_CHK && ignore)
 		{
@@ -12888,18 +12808,18 @@ fold_builtin_stxcpy_chk (location_t loc, tree fndecl, tree dest,
   if (fcode == BUILT_IN_STRCPY_CHK && operand_equal_p (src, dest, 0))
     return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), dest);
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_TREE;
 
   if (! integer_all_onesp (size))
     {
       len = c_strlen (src, 1);
-      if (! len || ! host_integerp (len, 1))
+      if (! len || ! tree_fits_uhwi_p (len))
 	{
 	  /* If LEN is not constant, try MAXLEN too.
 	     For MAXLEN only allow optimizing into non-_ocs function
 	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
-	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
+	  if (maxlen == NULL_TREE || ! tree_fits_uhwi_p (maxlen))
 	    {
 	      if (fcode == BUILT_IN_STPCPY_CHK)
 		{
@@ -12975,17 +12895,17 @@ fold_builtin_stxncpy_chk (location_t loc, tree dest, tree src,
          return build_call_expr_loc (loc, fn, 4, dest, src, len, size);
     }
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_TREE;
 
   if (! integer_all_onesp (size))
     {
-      if (! host_integerp (len, 1))
+      if (! tree_fits_uhwi_p (len))
 	{
 	  /* If LEN is not constant, try MAXLEN too.
 	     For MAXLEN only allow optimizing into non-_ocs function
 	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
-	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
+	  if (maxlen == NULL_TREE || ! tree_fits_uhwi_p (maxlen))
 	    return NULL_TREE;
 	}
       else
@@ -13024,7 +12944,7 @@ fold_builtin_strcat_chk (location_t loc, tree fndecl, tree dest,
   if (p && *p == '\0')
     return omit_one_operand_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
 
-  if (! host_integerp (size, 1) || ! integer_all_onesp (size))
+  if (! tree_fits_uhwi_p (size) || ! integer_all_onesp (size))
     return NULL_TREE;
 
   /* If __builtin_strcat_chk is used, assume strcat is available.  */
@@ -13058,15 +12978,15 @@ fold_builtin_strncat_chk (location_t loc, tree fndecl,
   else if (integer_zerop (len))
     return omit_one_operand_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_TREE;
 
   if (! integer_all_onesp (size))
     {
       tree src_len = c_strlen (src, 1);
       if (src_len
-	  && host_integerp (src_len, 1)
-	  && host_integerp (len, 1)
+	  && tree_fits_uhwi_p (src_len)
+	  && tree_fits_uhwi_p (len)
 	  && ! tree_int_cst_lt (len, src_len))
 	{
 	  /* If LEN >= strlen (SRC), optimize into __strcat_chk.  */
@@ -13115,7 +13035,7 @@ fold_builtin_sprintf_chk_1 (location_t loc, int nargs, tree *args,
   if (!validate_arg (fmt, POINTER_TYPE))
     return NULL_TREE;
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_TREE;
 
   len = NULL_TREE;
@@ -13146,7 +13066,7 @@ fold_builtin_sprintf_chk_1 (location_t loc, int nargs, tree *args,
 	      if (validate_arg (arg, POINTER_TYPE))
 		{
 		  len = c_strlen (arg, 1);
-		  if (! len || ! host_integerp (len, 1))
+		  if (! len || ! tree_fits_uhwi_p (len))
 		    len = NULL_TREE;
 		}
 	    }
@@ -13223,17 +13143,17 @@ fold_builtin_snprintf_chk_1 (location_t loc, int nargs, tree *args,
   if (!validate_arg (fmt, POINTER_TYPE))
     return NULL_TREE;
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_TREE;
 
   if (! integer_all_onesp (size))
     {
-      if (! host_integerp (len, 1))
+      if (! tree_fits_uhwi_p (len))
 	{
 	  /* If LEN is not constant, try MAXLEN too.
 	     For MAXLEN only allow optimizing into non-_ocs function
 	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
-	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
+	  if (maxlen == NULL_TREE || ! tree_fits_uhwi_p (maxlen))
 	    return NULL_TREE;
 	}
       else
@@ -13878,10 +13798,10 @@ do_mpfr_bessel_n (tree arg1, tree arg2, tree type,
   /* To proceed, MPFR must exactly represent the target floating point
      format, which only happens when the target base equals two.  */
   if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
-      && host_integerp (arg1, 0)
+      && tree_fits_shwi_p (arg1)
       && TREE_CODE (arg2) == REAL_CST && !TREE_OVERFLOW (arg2))
     {
-      const HOST_WIDE_INT n = tree_low_cst(arg1, 0);
+      const HOST_WIDE_INT n = tree_to_hwi(arg1);
       const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg2);
 
       if (n == (long)n
diff --git a/gcc/dfp.c b/gcc/dfp.c
index d15ee8f..f0172c1 100644
--- a/gcc/dfp.c
+++ b/gcc/dfp.c
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "tm_p.h"
 #include "dfp.h"
+#include "wide-int.h"
 
 /* The order of the following headers is important for making sure
    decNumber structure is large enough to hold decimal128 digits.  */
@@ -631,6 +632,33 @@ decimal_real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh,
   real_to_integer2 (plow, phigh, &to);
 }
 
+/* Likewise, but returns a wide_int with PRECISION.  Fail
+   is set if the value does not fit.  */
+
+wide_int
+decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision)
+{
+  decContext set;
+  decNumber dn, dn2, dn3;
+  REAL_VALUE_TYPE to;
+  char string[256];
+
+  decContextDefault (&set, DEC_INIT_DECIMAL128);
+  set.traps = 0;
+  set.round = DEC_ROUND_DOWN;
+  decimal128ToNumber ((const decimal128 *) r->sig, &dn);
+
+  decNumberToIntegralValue (&dn2, &dn, &set);
+  decNumberZero (&dn3);
+  decNumberRescale (&dn, &dn2, &dn3, &set);
+
+  /* Convert to REAL_VALUE_TYPE and call appropriate conversion
+     function.  */
+  decNumberToString (&dn, string);
+  real_from_string (&to, string);
+  return real_to_integer (&to, fail, precision);
+}
+
 /* Perform the decimal floating point operation described by CODE.
    For a unary operation, OP1 will be NULL.  This function returns
    true if the result may be inexact due to loss of precision.  */
diff --git a/gcc/real.c b/gcc/real.c
index b80aeac..7acc3df 100644
--- a/gcc/real.c
+++ b/gcc/real.c
@@ -29,6 +29,7 @@
 #include "realmpfr.h"
 #include "tm_p.h"
 #include "dfp.h"
+#include "wide-int.h"
 
 /* The floating point model used internally is not exactly IEEE 754
    compliant, and close to the description in the ISO C99 standard,
@@ -1459,6 +1460,91 @@ real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh,
   *phigh = high;
 }
 
+/* Likewise, but producing a wide-int of PRECISION.  If
+   the value cannot be represented in precision, FAIL is set to
+   TRUE.  */
+
+wide_int
+real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision)
+{
+  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  int exp;
+  int words;
+  wide_int result;
+  int w;
+
+  switch (r->cl)
+    {
+    case rvc_zero:
+    underflow:
+      return wide_int::zero (precision);
+
+    case rvc_inf:
+    case rvc_nan:
+    overflow:
+      *fail = true;
+      
+      if (r->sign)
+	return wide_int::set_bit_in_zero (precision, precision);
+      else
+	return ~wide_int::set_bit_in_zero (precision, precision);
+
+    case rvc_normal:
+      if (r->decimal)
+	return decimal_real_to_integer (r, fail, precision);
+
+      exp = REAL_EXP (r);
+      if (exp <= 0)
+	goto underflow;
+      /* Only force overflow for unsigned overflow.  Signed overflow is
+	 undefined, so it doesn't matter what we return, and some callers
+	 expect to be able to use this routine for both signed and
+	 unsigned conversions.  */
+      if (exp > precision)
+	goto overflow;
+
+      words = (precision + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT;
+
+      for (int i = 0; i < 2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT; i++)
+	val[i] = 0;
+
+#if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG)
+      for (int i = 0; i < words; i++)
+	{
+	  int j = SIGSZ - words + i;
+	  val[i] = (j < 0) ? 0 : r->sig[j]; 
+	}
+#else
+      gcc_assert (HOST_BITS_PER_WIDE_INT == 2*HOST_BITS_PER_LONG);
+      for (int i = 0; i < words; i++)
+	{
+	  int j = SIGSZ - (words * 2) + (i + 2) + 1;
+	  if (j < 0)
+	    val[i] = 0;
+	  else 
+	    {
+	      val[i] = r->sig[j];
+	      val[i] <<= HOST_BITS_PER_LONG;
+	      val[i] |= r->sig[j - 1];
+	    }
+	}
+#endif 
+      w = SIGSZ * HOST_BITS_PER_LONG + words * HOST_BITS_PER_WIDE_INT; 
+      result = wide_int::from_array (val, 
+	  (w + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT, w, w); 
+      result = result.rshiftu ((words * HOST_BITS_PER_WIDE_INT) - exp);
+      result = result.force_to_size (precision, wide_int::UNSIGNED);
+
+      if (r->sign)
+	return result.neg ();
+      else
+	return result;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* A subroutine of real_to_decimal.  Compute the quotient and remainder
    of NUM / DEN.  Return the quotient and place the remainder in NUM.
    It is expected that NUM / DEN are close enough that the quotient is
diff --git a/gcc/tree.h b/gcc/tree.h
index be43440..2bd4132 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -735,6 +735,8 @@ enum tree_node_structure_enum {
 };
 #undef DEFTREESTRUCT
 
+#define NULL_TREE (tree) NULL
+
 /* Define accessors for the fields that all tree nodes have
    (though some fields are not used for all kinds of nodes).  */
 
@@ -4101,6 +4103,113 @@ omp_clause_elt_check (const_tree __t, int __i,
 
 #endif
 
+/* Return true if T is an INTEGER_CST whose value must be non-negative
+   and can be represented in a single unsigned HOST_WIDE_INT.  */
+
+static inline bool
+tree_fits_uhwi_p (const_tree cst)
+{
+  if (cst == NULL_TREE)
+    return false;
+
+  if (TREE_CODE (cst) != INTEGER_CST)
+    return false;
+
+#ifdef NEW_REP_FOR_INT_CST
+  return TREE_INT_CST_NUNITS (cst) == 1 
+    || (TREE_INT_CST_NUNITS (cst) == 2 && TREE_INT_CST_ELT[1] == 0);
+
+#else
+  return (TREE_INT_CST_HIGH (cst) == 0);
+#endif
+}
+
+/* Return true if CST is an INTEGER_CST whose value can be represented
+   in a single HOST_WIDE_INT.  */
+
+static inline bool
+tree_fits_shwi_p (const_tree cst)
+{
+  if (cst == NULL_TREE)
+    return false;
+
+  if (TREE_CODE (cst) != INTEGER_CST)
+    return false;
+
+#ifdef NEW_REP_FOR_INT_CST
+  return TREE_INT_CST_NUNITS (cst) == 1;
+#else
+  return ((TREE_INT_CST_HIGH (cst) == 0
+	   && (HOST_WIDE_INT) TREE_INT_CST_LOW (cst) >= 0)
+	  || (TREE_INT_CST_HIGH (cst) == -1
+	      && (HOST_WIDE_INT) TREE_INT_CST_LOW (cst) < 0
+	      && !TYPE_UNSIGNED (TREE_TYPE (cst))));
+#endif
+}
+
+/* Return true if T is an INTEGER_CST that can be manipulated
+   efficiently on the host.  If POS is false, the value can be
+   represented in a single HOST_WIDE_INT.  If POS is true, the value
+   must be non-negative and can be represented in a single unsigned
+   HOST_WIDE_INT.  */
+
+static inline bool
+tree_fits_hwi_p (const_tree cst, bool pos)
+{
+  if (cst == NULL_TREE)
+    return 0;
+
+  if (TREE_CODE (cst) != INTEGER_CST)
+    return false;
+
+  return pos ? tree_fits_uhwi_p (cst) : tree_fits_shwi_p (cst);
+}
+
+/* Return the unsigned HOST_WIDE_INT least significant bits of CST.
+   If checking is enabled, this ices if the value does not fit.  */
+
+static inline unsigned HOST_WIDE_INT
+tree_to_uhwi (const_tree cst)
+{
+  gcc_checking_assert (tree_fits_uhwi_p (cst));
+
+#ifdef NEW_REP_FOR_INT_CST
+  return (unsigned HOST_WIDE_INT)TREE_INT_CST_ELT (cst, 0);
+#else
+  return (unsigned HOST_WIDE_INT)TREE_INT_CST_LOW (cst);
+#endif
+}
+
+/* Return the HOST_WIDE_INT least significant bits of CST.  If
+   checking is enabled, this ices if the value does not fit.  */
+
+static inline HOST_WIDE_INT
+tree_to_shwi (const_tree cst)
+{
+  gcc_checking_assert (tree_fits_shwi_p (cst));
+
+#ifdef NEW_REP_FOR_INT_CST
+  return (HOST_WIDE_INT)TREE_INT_CST_ELT (cst, 0);
+#else
+  return (HOST_WIDE_INT)TREE_INT_CST_LOW (cst);
+#endif
+}
+
+/* Return the HOST_WIDE_INT least significant bits of CST.  No
+   checking is done to assure that it fits.  It is assumed that one of
+   tree_fits_uhwi_p or tree_fits_shwi_p was done before this call. */
+
+static inline HOST_WIDE_INT
+tree_to_hwi (const_tree cst)
+{
+#ifdef NEW_REP_FOR_INT_CST
+  return TREE_INT_CST_ELT (cst, 0);
+#else
+  return TREE_INT_CST_LOW (cst);
+#endif
+}
+
+
 /* Compute the number of operands in an expression node NODE.  For
    tcc_vl_exp nodes like CALL_EXPRs, this is stored in the node itself,
    otherwise it is looked up from the node's code.  */
@@ -4568,8 +4677,6 @@ enum ptrmemfunc_vbit_where_t
   ptrmemfunc_vbit_in_delta
 };
 \f
-#define NULL_TREE (tree) NULL
-
 /* True if NODE is an erroneous expression.  */
 
 #define error_operand_p(NODE)					\

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-17  0:49                                                                                 ` Kenneth Zadeck
  2013-04-17  3:41                                                                                   ` patch to fix constant math -5th patch, rtl Kenneth Zadeck
  2013-04-17  7:34                                                                                   ` patch to fix constant math - builtins.c - the first of the tree level patches for wide-int Kenneth Zadeck
@ 2013-04-17 15:01                                                                                   ` Kenneth Zadeck
  2013-04-19 15:35                                                                                   ` Richard Biener
  3 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-17 15:01 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 2958 bytes --]

richard,

here is a copy of the patch without the debugging that you asked me to 
remove.
I forgot to remove it before sending this patch.

kenny

On 04/16/2013 04:07 PM, Kenneth Zadeck wrote:
> Richard,
>
> I made major changes to wide-int along the lines you suggested. Each 
> of the binary operations is now a template.
> There are 5 possible implementations of those operations, one for each 
> of HWI, unsigned HWI, wide-int, rtl, and tree.   Note that this is not 
> exactly as you suggested, but it is along the same lines.
>
> The HWI template sign extends the value to the precision of the first 
> operand, the unsigned HWI is the same except that it is an unsigned 
> extension.   The wide-int version is used as before, but is in truth 
> rarely used.  The rtl and tree "logically" convert the value to a 
> wide-int but in practice do something more efficient than converting 
> to the wide-int.   What they do is look inside the rtl or the tree and 
> pass a pointer to the data and a length to the binary operation.  This 
> is perfectly safe in the position of a second operand to the binary 
> operation because the lifetime is guaranteed to be very short.  The 
> wide-int implementation was also modified to do the same pointer trick 
> allowing all 5 templates to share the same use of the data.
>
> Note that currently the tree code is more crufty than one would 
> like.   This will clean up nicely when the tree-cst is changed to 
> represent the value with an array and a length field.
>
> So now, at least for the second operand of binary operations, the 
> storage is never copied.    I do not believe that there is a good 
> similar trick for the first operand.  i did not consider something 
> like wide_int::add (a, b) to be a viable option; it seems to mis the 
> point of using an object oriented language.   So I think that you 
> really have to copy the data into an instance of a wide int.
>
> However, while all of this avoids ever having to pass a precision into 
> the second operand, this patch does preserve the finite math 
> implementation of wide-int.    Finite math is really what people 
> expect an optimizer to do, because it seamlessly matches what the 
> machine is going to do.
>
> I hope at this point, i can get a comprehensive review on these 
> patches.   I believe that I have done what is required.
>
> There are two other patches that will be submitted in the next few 
> minutes.   The first one is an updated version of the rtl level 
> patch.   The only changes from what you have seen before are that the 
> binary operations now use the templated binary operations. The second 
> one is the first of the tree level patches.   It converts builtins.c 
> to use both use wide-int and it removes all assumptions that tree-csts 
> are built with two HWIs.
>
> Once builtins.c is accepted, i will convert the rest of the middle end 
> patches.   They will all be converted in a similar way.
>
> Kenny


[-- Attachment #2: p4-6.diff --]
[-- Type: text/x-patch, Size: 136849 bytes --]

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 109f865..514fabc 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -857,7 +857,7 @@ RTL_BASE_H = coretypes.h rtl.h rtl.def $(MACHMODE_H) reg-notes.def \
   insn-notes.def $(INPUT_H) $(REAL_H) statistics.h $(VEC_H) \
   $(FIXED_VALUE_H) alias.h $(HASHTAB_H)
 FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h
-RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h
+RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h wide-int.h
 RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H)
 READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
 PARAMS_H = params.h params.def
@@ -945,7 +945,7 @@ TREE_PRETTY_PRINT_H = tree-pretty-print.h $(PRETTY_PRINT_H)
 GIMPLE_PRETTY_PRINT_H = gimple-pretty-print.h $(TREE_PRETTY_PRINT_H)
 DIAGNOSTIC_CORE_H = diagnostic-core.h $(INPUT_H) bversion.h diagnostic.def
 DIAGNOSTIC_H = diagnostic.h $(DIAGNOSTIC_CORE_H) $(PRETTY_PRINT_H)
-DWARF2OUT_H = dwarf2out.h $(DWARF2_H)
+DWARF2OUT_H = dwarf2out.h $(DWARF2_H) wide-int.h
 C_PRETTY_PRINT_H = c-family/c-pretty-print.h $(PRETTY_PRINT_H) \
 	$(C_COMMON_H) $(TREE_H)
 SCEV_H = tree-scalar-evolution.h $(GGC_H) tree-chrec.h $(PARAMS_H)
@@ -1458,6 +1458,7 @@ OBJS = \
 	varpool.o \
 	vmsdbgout.o \
 	web.o \
+	wide-int.o \
 	xcoffout.o \
 	$(out_object_file) \
 	$(EXTRA_OBJS) \
@@ -2687,6 +2688,7 @@ targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
    tree-ssa-alias.h $(TREE_FLOW_H)
 common/common-targhooks.o : common/common-targhooks.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(INPUT_H) $(TM_H) $(COMMON_TARGET_H) common/common-targhooks.h
+wide-int.o: wide-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
 
 bversion.h: s-bversion; @true
 s-bversion: BASE-VER
@@ -2853,10 +2855,10 @@ emit-rtl.o : emit-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(HASHTAB_H) $(TM_P_H) debug.h langhooks.h $(TREE_PASS_H) gt-emit-rtl.h \
    $(DF_H) $(PARAMS_H) $(TARGET_H)
 real.o : real.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
-   $(DIAGNOSTIC_CORE_H) $(TM_P_H) $(REAL_H) dfp.h realmpfr.h
+   $(DIAGNOSTIC_CORE_H) $(TM_P_H) $(REAL_H) dfp.h realmpfr.h wide-int.h
 realmpfr.o : realmpfr.c realmpfr.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(REAL_H) $(TREE_H)
 dfp.o : dfp.c dfp.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H)	$(TREE_H) \
-   $(TM_P_H) $(REAL_H) $(DECNUM_H)
+   $(TM_P_H) $(REAL_H) $(DECNUM_H) wide-int.h
 fixed-value.o: fixed-value.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) $(REAL_H) $(DIAGNOSTIC_CORE_H)
 jump.o : jump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
@@ -3941,15 +3943,16 @@ CFLAGS-gengtype-parse.o += -DGENERATOR_FILE
 build/gengtype-parse.o: $(BCONFIG_H)
 
 gengtype-state.o build/gengtype-state.o: gengtype-state.c $(SYSTEM_H) \
-  gengtype.h errors.h double-int.h version.h $(HASHTAB_H) $(OBSTACK_H) \
-  $(XREGEX_H)
+  gengtype.h errors.h double-int.h version.h $(HASHTAB_H)    \
+  $(OBSTACK_H) $(XREGEX_H)
 gengtype-state.o: $(CONFIG_H)
 CFLAGS-gengtype-state.o += -DGENERATOR_FILE
 build/gengtype-state.o: $(BCONFIG_H)
-
+wide-int.h: $(GTM_H) $(TREE_H) hwint.h $(OPTIONS_H) $(TM_H)             \
+  $(MACHMODE_H) double-int.h dumpfile.h $(REAL_H)
 gengtype.o build/gengtype.o : gengtype.c $(SYSTEM_H) gengtype.h 	\
-  rtl.def insn-notes.def errors.h double-int.h version.h $(HASHTAB_H) \
-  $(OBSTACK_H) $(XREGEX_H)
+  rtl.def insn-notes.def errors.h double-int.h wide-int.h version.h     \
+  $(HASHTAB_H) $(OBSTACK_H) $(XREGEX_H)
 gengtype.o: $(CONFIG_H)
 CFLAGS-gengtype.o += -DGENERATOR_FILE
 build/gengtype.o: $(BCONFIG_H)
diff --git a/gcc/wide-int.c b/gcc/wide-int.c
new file mode 100644
index 0000000..1ba2ca4
--- /dev/null
+++ b/gcc/wide-int.c
@@ -0,0 +1,2727 @@
+/* Operations with very long integers.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hwint.h"
+#include "wide-int.h"
+#include "rtl.h"
+#include "tree.h"
+#include "dumpfile.h"
+
+/* This is the maximal size of the buffer needed for dump.  */
+const int MAX_SIZE = 4 * (MAX_BITSIZE_MODE_ANY_INT / 4
+		     + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
+
+/*
+ * Internal utilities.
+ */
+
+/* Quantities to deal with values that hold half of a wide int.  Used
+   in multiply and divide.  */
+#define HALF_INT_MASK (((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1)
+
+#define BLOCK_OF(TARGET) ((TARGET) / HOST_BITS_PER_WIDE_INT)
+#define BLOCKS_NEEDED(PREC) \
+  (((PREC) + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+#define SIGN_MASK(X) (((HOST_WIDE_INT)X) >> (HOST_BITS_PER_WIDE_INT - 1))
+/*
+ * Conversion routines in and out of wide-int.
+ */
+
+/* Convert OP0 into a wide int of PRECISION.  If the precision is less
+   than HOST_BITS_PER_WIDE_INT, zero extend the value of the word.
+   The overflow bit are set if the number was too large to fit in the
+   mode.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0,
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT t = sext_hwi (op0, precision);
+      if (t != op0 && overflow)
+	*overflow = true; 
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+  result.len = 1;
+
+  return result;
+}
+
+/* Convert OP0 into a wide int of PRECISION.  If the precision is less
+   than HOST_BITS_PER_WIDE_INT, zero extend the value of the word.
+   The overflow bit are set if the number was too large to fit in the
+   mode.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, 
+		     unsigned int precision, bool *overflow)
+{
+  wide_int result;
+
+  result.precision = precision;
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT t = zext_hwi (op0, precision);
+      if (t != op0 && overflow)
+	*overflow = true;
+      op0 = t;
+    }
+
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && precision > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+  return result;
+}
+
+/* Create a wide_int from an array of host_wide_ints in OP1 of LEN.
+   The result has PRECISION.  */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT *op1, unsigned int len, 
+		      unsigned int precision, bool need_canon)
+{
+  unsigned int i;
+  wide_int result;
+  
+  result.len = len;
+  result.precision = precision;
+
+  for (i=0; i < len; i++)
+    result.val[i] = op1[i];
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Convert a double int into a wide int with precision PREC.  */
+
+wide_int
+wide_int::from_double_int (double_int di, unsigned int prec)
+{
+  HOST_WIDE_INT op = di.low;
+  wide_int result;
+
+  result.precision = prec;
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result.val[0] = sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    result.val[1] = sext_hwi (di.high, prec);
+	  else
+	    result.val[1] = di.high;
+	}
+    }
+
+  if (result.len == 2)
+    result.canonize ();
+
+  return result;
+}
+
+/* Convert a integer cst into a wide int.  */
+
+wide_int
+wide_int::from_tree (const_tree tcst)
+{
+  wide_int result;
+  tree type = TREE_TYPE (tcst);
+  unsigned int prec = TYPE_PRECISION (type);
+
+  result.precision = prec;
+
+  /* This will simplify out to just an array copy and a len copy.  */
+  result.val[0] = TREE_INT_CST_LOW (tcst);
+  result.val[1] = TREE_INT_CST_HIGH (tcst);
+  if (prec == HOST_BITS_PER_DOUBLE_INT 
+      && TYPE_UNSIGNED (type)
+      && TREE_INT_CST_HIGH (tcst) < 0)
+    {
+      result.val[2] = 0;
+      result.len = 3;
+    }
+  else if (prec > HOST_BITS_PER_WIDE_INT)
+    result.len = 2;
+  else if (prec == HOST_BITS_PER_WIDE_INT
+	   && TYPE_UNSIGNED (type)
+	   && (HOST_WIDE_INT)TREE_INT_CST_LOW (tcst) < 0)
+    result.len = 2;
+  else
+    result.len = 1;
+
+  return result;
+}
+
+/* Extract a constant integer from the X of type MODE.  The bits of
+   the integer are returned.  */
+
+wide_int
+wide_int::from_rtx (const_rtx x, enum machine_mode mode)
+{
+  wide_int result;
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  gcc_assert (mode != VOIDmode);
+
+  result.precision = prec;
+
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+      result.val[0] = INTVAL (x);
+      result.len = 1;
+      break;
+
+#if TARGET_SUPPORTS_WIDE_INT
+    case CONST_WIDE_INT:
+      {
+	int i;
+	result.len = CONST_WIDE_INT_NUNITS (x);
+	
+	for (i = 0; i < result.len; i++)
+	  result.val[i] = CONST_WIDE_INT_ELT (x, i);
+      }
+      break;
+#else
+    case CONST_DOUBLE:
+      result.len = 2;
+      result.val[0] = CONST_DOUBLE_LOW (x);
+      result.val[1] = CONST_DOUBLE_HIGH (x);
+      break;
+#endif
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return result;
+}
+
+/* Construct from a buffer of length LEN.  BUFFER will be read according
+   to byte endianess and word endianess.  Only the lower LEN bytes
+   of the result are set; the remaining high bytes are cleared.  */
+
+wide_int
+wide_int::from_buffer (const unsigned char *buffer, int len)
+{
+  wide_int result = wide_int::zero (len * BITS_PER_UNIT);
+  int words = len / UNITS_PER_WORD;
+
+  for (int byte = 0; byte < len; byte++)
+    {
+      int offset;
+      int index;
+      int bitpos = byte * BITS_PER_UNIT;
+      unsigned HOST_WIDE_INT value;
+
+      if (len > UNITS_PER_WORD)
+	{
+	  int word = byte / UNITS_PER_WORD;
+
+	  if (WORDS_BIG_ENDIAN)
+	    word = (words - 1) - word;
+
+	  offset = word * UNITS_PER_WORD;
+
+	  if (BYTES_BIG_ENDIAN)
+	    offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
+	  else
+	    offset += byte % UNITS_PER_WORD;
+	}
+      else
+	offset = BYTES_BIG_ENDIAN ? (len - 1) - byte : byte;
+
+      value = (unsigned HOST_WIDE_INT) buffer[offset];
+
+      index = bitpos / HOST_BITS_PER_WIDE_INT;
+      result.val[index] |= value << bitpos;
+    }
+
+  result.canonize ();
+  return result;
+}
+
+
+/*
+ * Largest and smallest values in a mode.
+ */
+
+/* Produce the largest SGNed number that is represented in PREC.  The
+   resulting number is placed in a wide int of size PRECISION.  */
+
+wide_int
+wide_int::max_value (unsigned int prec, unsigned int precision, 
+		     SignOp sgn)
+{
+  wide_int result;
+  
+  result.precision = precision;
+
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned max is just all ones, for which the compressed
+	 rep is just a single HWI.  */ 
+      result.len = 1;
+      result.val[0] = (HOST_WIDE_INT)-1;
+    }
+  else
+    {
+      /* The signed max is all ones except the top bit.  This must be
+	 explicitly represented.  */
+      int i;
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      int shift = (small_prec == 0) 
+	? HOST_BITS_PER_WIDE_INT - 1 : small_prec - 1;
+
+      result.len = BLOCKS_NEEDED (prec);
+      for (i = 0; i < result.len - 1; i++)
+	result.val[i] = (HOST_WIDE_INT)-1;
+
+      result.val[result.len - 1] = ((HOST_WIDE_INT)1 << shift) - 1;
+    }
+  
+  return result;
+}
+
+/* Produce the smallest SGNed number that is represented in PREC.  The
+   resulting number is placed in a wide int of size PRECISION.  */
+
+wide_int
+wide_int::min_value (unsigned int prec, unsigned int precision, 
+		     SignOp sgn)
+{
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned min is just all zeros, for which the compressed
+	 rep is just a single HWI.  */ 
+      wide_int result;
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = 0;
+      return result;
+    }
+  else
+    {
+      /* The signed min is all zeros except the top bit.  This must be
+	 explicitly represented.  */
+      return set_bit_in_zero (prec - 1, precision);
+    }
+}
+
+/*
+ * Public utilities.
+ */
+
+/* Check the upper HOST_WIDE_INTs of src to see if the length can be
+   shortened.  An upper HOST_WIDE_INT is unnecessary if it is all ones
+   or zeros and the top bit of the next lower word matches.
+
+   This function may change the representation of THIS, but does not
+   change the value that THIS represents.  It does not sign extend in
+   the case that the size of the mode is less than
+   HOST_BITS_PER_WIDE_INT.  */
+
+void
+wide_int::canonize ()
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT top;
+  int i;
+
+  if (len > blocks_needed)
+    len = blocks_needed;
+
+  /* Clean up the top bits for any mode that is not a multiple of a HWI.  */
+  if (len == blocks_needed && small_prec)
+    val[len - 1] = sext_hwi (val[len - 1], small_prec);
+
+  if (len == 1)
+    return;
+
+  top = val[len - 1];
+  if (top != 0 && top != (HOST_WIDE_INT)-1)
+    return;
+
+  /* At this point we know that the top is either 0 or -1.  Find the
+     first block that is not a copy of this.  */
+  for (i = len - 2; i >= 0; i--)
+    {
+      HOST_WIDE_INT x = val[i];
+      if (x != top)
+	{
+	  if (SIGN_MASK (x) == top)
+	    {
+	      len = i + 1;
+	      return;
+	    }
+
+	  /* We need an extra block because the top bit block i does
+	     not match the extension.  */
+	  len = i + 2;
+	  return;
+	}
+    }
+
+  /* The number is 0 or -1.  */
+  len = 1;
+}
+
+
+/* Make a copy of this.  */
+
+wide_int
+wide_int::copy () const
+{
+  wide_int result;
+  int i;
+
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+  return result;
+}
+
+
+/* Copy THIS replacing the precision with PREC.
+   It can do any of truncation, extension or copying.  */
+
+wide_int
+wide_int::force_to_size (unsigned int prec, SignOp sgn) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (prec);
+  int i;
+
+  result.precision = prec;
+  result.len = blocks_needed < len ? blocks_needed : len;
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+
+  if (prec >= precision) 
+    {
+      /* Expanding */
+      int small_precision = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+      /* The only case we care about is unsigned because the rep is
+	 inherantly signed.  */
+      if (sgn == UNSIGNED)
+	{
+	  /* The top block in the existing rep must be zero extended,
+	     but this is all the work we need to do.  */
+	  if (small_precision 
+	      && (len == BLOCKS_NEEDED (precision)
+		  || len == blocks_needed))
+	    result.val[len-1] = zext_hwi (result.val[len-1], small_precision);
+	  else if (len == BLOCKS_NEEDED (precision) 
+		   && len < blocks_needed
+		   && small_precision == 0
+		   && result.val[result.len - 1] < 0)
+		    /* We need to put the 0 block on top to keep the value
+		       from being sign extended.  */ 
+		    result.val[result.len++] = 0;
+	}
+    }
+  else
+    {
+      /* Truncating.  */
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      /* The only weird case we need to look at here is when we are
+         truncating within the top block.  We need to make sure that
+         everything in the block above the new precision is sign
+         extended.  Note that this is independent of the SGN.  This is
+         just to stay canonical.  */
+      if (small_prec && (blocks_needed == len))
+	result.val[blocks_needed-1]
+	  = sext_hwi (result.val[blocks_needed-1], small_prec);
+    }
+
+  return result;
+}
+
+/*
+ * public printing routines.
+ */
+
+/* Try to print the signed self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_DEC, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decs (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decs (buf);
+  fputs (buf, file);
+}
+
+/* Try to print the unsigned self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (char *buf) const
+{
+  if ((precision <= HOST_BITS_PER_WIDE_INT)
+      || (len == 1 && !neg_p ()))
+      sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, val[0]);
+  else
+    print_hex (buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+wide_int::print_decu (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decu (buf);
+  fputs (buf, file);
+}
+
+void 
+wide_int::print_hex (char *buf) const
+{
+  int i = len;
+
+  if (zero_p ())
+    sprintf (buf, "0x");
+  else
+    {
+      if (neg_p ())
+	{
+	  int j;
+	  /* If the number is negative, we may need to pad value with
+	     0xFFF...  because the leading elements may be missing and
+	     we do not print a '-' with hex.  */
+	  for (j = BLOCKS_NEEDED (precision); j > i; j--)
+	    buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, (HOST_WIDE_INT) -1);
+	    
+	}
+      else
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_HEX, val [--i]);
+      while (-- i >= 0)
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, val [i]);
+    }
+}
+
+/* Print one big hex number to FILE.  Note that some assemblers may not
+   accept this for large modes.  */
+void 
+wide_int::print_hex (FILE *file) const
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_hex (buf);
+  fputs (buf, file);
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently singed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+bool
+wide_int::eq_p_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  HOST_WIDE_INT op0mask = sign_mask ();
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  while (l0 > l1)
+    if (val[l0--] != op1mask)
+      return false;
+
+  while (l1 > l0)
+    if (op1[l1--] != op0mask)
+      return false;
+
+  while (l0 >= 0)
+    if (val[l0--] != op1[l1--])
+      return false;
+
+  return true;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p_large (const HOST_WIDE_INT *op0, unsigned int op0len, 
+		       const HOST_WIDE_INT *op1, unsigned int op1len, 
+		       unsigned int precision)
+{
+  int l;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  unsigned int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT op0mask = SIGN_MASK (op0[op0len - 1]);
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == op0len ? op0[blocks_needed - 1] : op0mask;
+  s1 = blocks_needed == op1len ? op1[blocks_needed - 1] : op1mask;
+  if (s0 < s1)
+    return true;
+  if (s0 > s1)
+    return false;
+
+  l = (signed int)MAX (op0len, op1len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == (signed int)blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < (signed int)op0len ? op0[l] : op0mask;
+      u1 = l < (signed int)op1len ? op1[l] : op1mask;
+
+      if (u0 < u1)
+	return true;
+      if (u0 > u1)
+	return false;
+      l--;
+    }
+
+  return false;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+int
+wide_int::cmps_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  int l;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  unsigned int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT op0mask = sign_mask ();
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == (unsigned int)len ? val[blocks_needed - 1] : op0mask;
+  s1 = blocks_needed == op1len ? op1[blocks_needed - 1] : op1mask;
+  if (s0 < s1)
+    return -1;
+  if (s0 > s1)
+    return 1;
+
+  l = MAX (len, (signed int)op1len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == (signed int)blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < len ? val [l] : op0mask;
+      u1 = l < (signed int)op1len ? op1[l] : op1mask;
+
+      if (u0 < u1)
+	return -1;
+      if (u0 > u1)
+	return 1;
+      l--;
+    }
+
+  return 0;
+}
+
+/* Return true if OP0 < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p_large (const HOST_WIDE_INT *op0, unsigned int op0len, 
+		       const HOST_WIDE_INT *op1, unsigned int op1len)
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = op0len - 1;
+  int l1 = op1len - 1;
+  HOST_WIDE_INT op0mask = SIGN_MASK (op0[op0len - 1]);
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  while (l0 > l1)
+    {
+      x0 = op0[l0--];
+      x1 = op1mask;
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  while (l1 > l0)
+    {
+      x0 = op0mask;
+      x1 = op1[l1--];
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = op0[l0--];
+      x1 = op1[l1--];
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  return false;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+int
+wide_int::cmpu_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  HOST_WIDE_INT op0mask = sign_mask ();
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1mask;
+      if (x0 < x1)
+	return -1;
+      else if (x0 > x1)
+	return 1;
+    }
+
+  while (l1 > l0)
+    {
+      x0 = op0mask;
+      x1 = op1[l1--];
+      if (x0 < x1)
+	return -1;
+      if (x0 > x1)
+	return 1;
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1[l1--];
+      if (x0 < x1)
+	return -1;
+      if (x0 > x1)
+	return 1;
+    }
+
+  return 0;
+}
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p (unsigned int prec) const
+{
+  int i;
+  HOST_WIDE_INT x;
+  int small_prec;
+  bool result;
+
+  if (BLOCKS_NEEDED (prec) != len)
+    {
+      result = false;
+      goto ex;
+    }
+
+  for (i=0; i < len - 1; i++)
+    if (val[i] != 0)
+      {
+	result = false;
+	goto ex;
+      }
+
+  x = val[len - 1];
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec)
+    x = x << (HOST_BITS_PER_WIDE_INT - small_prec);
+
+  result = x == ((HOST_WIDE_INT)1) << (HOST_BITS_PER_WIDE_INT - 1);
+
+ ex:
+  return result;
+}
+
+/* Returns true if THIS fits into range of TYPE.  Signedness of OP0 is
+   assumed to be the same as the signedness of TYPE.  */
+
+bool
+wide_int::fits_to_tree_p (const_tree type) const
+{
+  int type_prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return fits_u_p (type_prec);
+  else
+    return fits_s_p (type_prec);
+}
+
+/* Returns true of THIS fits in the unsigned range of precision.  */
+
+bool
+wide_int::fits_s_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == sext (prec);
+}
+
+
+/* Returns true if THIS fits into range of TYPE.  */
+
+bool
+wide_int::fits_u_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == zext (prec);
+}
+
+/*
+ * Extension.
+ */
+
+/* Sign extend THIS starting at OFFSET.  The precision of the result
+   are the same as THIS.  */
+
+wide_int
+wide_int::sext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = sext_hwi (val[0], offset);
+      else
+	/* If offset is greater or equal to precision there is nothing
+	   to do since the internal rep is already sign extended.  */
+	result.val[0] = val[0];
+
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, precision);
+      
+      /* Now we can do the real sign extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      if (off)
+	{
+	  int block = BLOCK_OF (offset);
+	  result.val[block] = sext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      /* We never need an extra element for sign extended values.  */
+    }    
+
+  return result;
+}
+
+/* Zero extend THIS starting at OFFSET.  The precision of the result
+   are the same as THIS.  */
+
+wide_int
+wide_int::zext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+  int block;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = zext_hwi (val[0], offset);
+      else if (offset == precision)
+	result.val[0] = val[0];
+	/* If offset was greater than the precision we need to zero
+	   extend from the old precision since the internal rep was
+	   equivalent to sign extended.  */
+      else
+	result.val[0] = zext_hwi (val[0], precision);
+	
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, precision);
+
+      /* Now we can do the real zero extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      block = BLOCK_OF (offset);
+      if (off)
+	{
+	  result.val[block] = zext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      else
+	/* See if we need an extra zero element to satisfy the
+	   compression rule.  */
+	if (val[block - 1] < 0 && offset < precision)
+	  {
+	    result.val[block] = 0;
+	    result.len += 1;
+	  }
+    }
+  return result;
+}
+
+/*
+ * Masking, inserting, shifting, rotating.
+ */
+
+/* Return a value with a one bit inserted in THIS at BITPOS.  */
+
+wide_int
+wide_int::set_bit (unsigned int bitpos) const
+{
+  wide_int result;
+  int i, j;
+
+  if (bitpos >= precision)
+    result = copy ();
+  else
+    {
+      result = decompress (bitpos, precision);
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+  return result;
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with PRECISION.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, unsigned int prec)
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (bitpos + 1);
+  int i, j;
+
+  result.precision = prec;
+  if (bitpos >= prec)
+    {
+      result.len = 1;
+      result.val[0] = 0;
+    }
+  else
+    {
+      result.len = blocks_needed;
+      for (i = 0; i < blocks_needed; i++)
+	result.val[i] = 0;
+      
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+  return result;
+}
+
+/* Insert WIDTH bits from OP0 into THIS starting at START.  */
+
+wide_int
+wide_int::insert (const wide_int &op0, unsigned int start, 
+		  unsigned int width) const
+{
+  wide_int result;
+  wide_int mask;
+  wide_int tmp;
+
+  if (start + width >= precision) 
+    width = precision - start;
+
+  mask = shifted_mask (start, width, false, precision);
+  tmp = op0.lshift (start, 0, precision, NONE);
+  result = tmp & mask;
+
+  tmp = and_not (mask);
+  result = result | tmp;
+
+  return result;
+}
+
+/* bswap THIS.  */
+
+wide_int
+wide_int::bswap () const
+{
+  wide_int result;
+  int i, s;
+  int end;
+  int len = BLOCKS_NEEDED (precision);
+
+  /* This is not a well defined operation if the precision is not a
+     multiple of 8.  */
+  gcc_assert ((precision & 0x7) == 0);
+
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < len; i++)
+    result.val[i] = 0;
+
+  /* Only swap the bytes that are not the padding.  */
+  if ((precision & (HOST_BITS_PER_WIDE_INT - 1))
+      && (this->len == len))
+    end = precision;
+  else
+    end = this->len * HOST_BITS_PER_WIDE_INT;
+
+  for (s = 0; s < end; s += 8)
+    {
+      unsigned int d = precision - s - 8;
+      unsigned HOST_WIDE_INT byte;
+
+      int block = s / HOST_BITS_PER_WIDE_INT;
+      int offset = s & (HOST_BITS_PER_WIDE_INT - 1);
+
+      byte = (val[block] >> offset) & 0xff;
+
+      block = d / HOST_BITS_PER_WIDE_INT;
+      offset = d & (HOST_BITS_PER_WIDE_INT - 1);
+
+      result.val[block] |= byte << offset;
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with PREC. */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  int shift;
+
+  gcc_assert (width < 2 * MAX_BITSIZE_MODE_ANY_INT);
+  gcc_assert (prec <= 2 * MAX_BITSIZE_MODE_ANY_INT);
+
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (prec);
+      else
+	result = wide_int::zero (prec);
+    }
+  else
+    {
+      result.precision = prec;
+      
+      while (i < width / HOST_BITS_PER_WIDE_INT)
+	result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+      
+      shift = width & (HOST_BITS_PER_WIDE_INT - 1);
+      if (shift != 0)
+	{
+	  HOST_WIDE_INT last = (((HOST_WIDE_INT)1) << shift) - 1;
+	  result.val[i++] = negate ? ~last : last;
+	}
+      result.len = i;
+    }
+
+  return result;
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  */
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  unsigned int shift;
+  unsigned int end = start + width;
+  HOST_WIDE_INT block;
+
+  if (start + width > prec)
+    width = prec - start;
+ 
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (prec);
+      else
+	result = wide_int::zero (prec);
+      return result;
+    }
+
+  result.precision = prec;
+
+  while (i < start / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? (HOST_WIDE_INT)-1 : 0;
+
+  shift = start & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift)
+    {
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      shift = (end) & (HOST_BITS_PER_WIDE_INT - 1);
+      if (shift)
+	{
+	  /* case 000111000 */
+	  block = (((HOST_WIDE_INT)1) << shift) - block - 1;
+	  result.val[i++] = negate ? ~block : block;
+	  result.len = i;
+	  return result;
+	}
+      else
+	/* ...111000 */
+	result.val[i++] = negate ? block : ~block;
+    }
+
+  while (i < end / HOST_BITS_PER_WIDE_INT)
+    /* 1111111 */
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = end & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      /* 000011111 */
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~block : block;
+    }
+
+  result.len = i;
+  return result;
+}
+
+
+/*
+ * logical operations.
+ */
+
+/* Return THIS & OP1.  */
+
+wide_int
+wide_int::and_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (SIGN_MASK (op1[op1len - 1]) == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & op1[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Return THIS & ~OP1.  */
+
+wide_int
+wide_int::and_not_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (SIGN_MASK (op1[op1len - 1]) != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & ~op1[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+wide_int
+wide_int::or_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (SIGN_MASK (op1[op1len - 1]) != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | op1[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+  return result;
+}
+
+/* Return THIS | ~OP1.  */
+
+wide_int
+wide_int::or_not_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (SIGN_MASK (op1[op1len - 1]) == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | ~op1[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Return the exclusive ior (xor) of THIS and OP1.  */
+
+wide_int
+wide_int::xor_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  while (l0 > l1)
+    {
+      result.val[l0] = val[l0] ^ SIGN_MASK (op1[op1len - 1]);
+      l0--;
+    }
+
+  while (l1 > l0)
+    {
+      result.val[l1] = sign_mask () ^ op1[l1];
+      l1--;
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] ^ op1[l0];
+      l0--;
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/*
+ * math
+ */
+
+/* Absolute value of THIS.  */
+
+wide_int
+wide_int::abs () const
+{
+  if (sign_mask ())
+    return neg ();
+
+  wide_int result = copy ();
+  return result;
+}
+
+/* Add of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::add_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.precision = precision;
+  result.len = MAX (len, op1len);
+  mask0 = sign_mask ();
+  mask1 = SIGN_MASK (op1[op1len - 1]);
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1len ? (unsigned HOST_WIDE_INT)op1[i] : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 + mask1 + carry;
+      result.len++;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/* Add of OP0 and OP1 with overflow checking.  If the result overflows
+   within the precision, set OVERFLOW.  OVERFLOW is assumed to be
+   sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::add (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT old_carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int i, small_prec;
+
+  gcc_checking_assert (precision == op1.precision);
+
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < len; i++)
+    {
+      o0 = val[i];
+      o1 = op1.val[i];
+      x = o0 + o1 + carry;
+      result.val [i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+
+  /* Uncompress the rest.  */
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = val[i];
+      o1 = mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = mask0;
+      o1 = op1.val[i];
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 + mask1 + carry;
+      result.len++;
+      /* If we were short, we could not have overflowed.  */
+      goto ex;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (sgn == wide_int::SIGNED)
+	{
+	  if (((!(o0 ^ o1)) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
+	    *overflow = true;
+	}
+      else if (old_carry)
+	{
+	  if ((~o0) <= o1)
+	    *overflow = true;
+	}
+      else
+	{
+	  if ((~o0) < o1)
+	    *overflow = true;
+	}
+    }
+  else
+    {
+      if (sgn == wide_int::UNSIGNED)
+	{
+	  /* The caveat for unsigned is to get rid of the bits above
+	     the precision before doing the addition.  To check the
+	     overflow, clear these bits and then redo the last
+	     addition.  If there are any non zero bits above the prec,
+	     we overflowed. */
+	  o0 = zext_hwi (o0, small_prec);
+	  o1 = zext_hwi (o1, small_prec);
+	  x = o0 + o1 + old_carry;
+	  if (x >> small_prec)
+	    *overflow = true;
+	}
+      else 
+	{
+	  /* Overflow in this case is easy since we can see bits beyond
+	     the precision.  If the value computed is not the sign
+	     extended value, then we have overflow.  */
+	  unsigned HOST_WIDE_INT y = sext_hwi (x, small_prec);
+	  if (x != y)
+	    *overflow = true;
+	}
+    }
+
+ ex:
+  result.canonize ();
+  return result;
+}
+
+
+/* Count leading zeros of THIS but only looking at the bits in the
+   smallest HWI of size mode.  */
+
+wide_int
+wide_int::clz () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+    }
+  else
+    {
+      /* The high order block is special if it is the last block and the
+	 precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+	 have to clear out any ones above the precision before doing clz
+	 on this block.  */
+      if (BLOCKS_NEEDED (precision) == len && small_prec)
+	{
+	  v = zext_hwi (val[len - 1], small_prec);
+	  count = clz_hwi (v) - (HOST_BITS_PER_WIDE_INT - small_prec);
+	  start = len - 2;
+	  if (v != 0)
+	    return from_shwi (count, precision);
+	}
+      else
+	{
+	  count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+	  start = len - 1;
+	}
+      
+      for (i = start; i >= 0; i--)
+	{
+	  v = elt (i);
+	  count += clz_hwi (v);
+	  if (v != 0)
+	    break;
+	}
+    }
+  return from_shwi (count, precision);
+}
+
+/* Count the number of redundant leading bits of THIS.  Return result
+   as a HOST_WIDE_INT.  */
+
+wide_int
+wide_int::clrsb () const
+{
+  if (neg_p ())
+    return operator ~ ().clz () - 1;
+
+  return clz () - 1;
+}
+
+/* Count zeros of THIS.   */
+
+wide_int
+wide_int::ctz () const
+{
+  int i;
+  unsigned int count = 0;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int end;
+  bool more_to_do;
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+    }
+  else
+    {
+      /* The high order block is special if it is the last block and the
+	 precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+	 have to clear out any ones above the precision before doing clz
+	 on this block.  */
+      if (BLOCKS_NEEDED (precision) == len && small_prec)
+	{
+	  end = len - 1;
+	  more_to_do = true;
+	}
+      else
+	{
+	  end = len;
+	  more_to_do = false;
+	}
+      
+      for (i = 0; i < end; i++)
+	{
+	  v = val[i];
+	  count += ctz_hwi (v);
+	  if (v != 0)
+	    return wide_int::from_shwi (count, precision);
+	}
+      
+      if (more_to_do)
+	{
+	  v = zext_hwi (val[len - 1], small_prec);
+	  count = ctz_hwi (v);
+	  /* The top word was all zeros so we have to cut it back to prec,
+	     because we are counting some of the zeros above the
+	     interesting part.  */
+	  if (count > precision)
+	    count = precision;
+	}
+      else
+	/* Skip over the blocks that are not represented.  They must be
+	   all zeros at this point.  */
+	count = precision;
+    }
+
+  return wide_int::from_shwi (count, precision);
+}
+
+/* ffs of THIS.  */
+
+wide_int
+wide_int::ffs () const
+{
+  HOST_WIDE_INT count = ctz ().to_shwi ();
+  if (count == precision)
+    count = 0;
+  else
+    count += 1;
+  return wide_int::from_shwi (count, precision);
+}
+
+/* Subroutines of the multiplication and division operations.  Unpack
+   the first IN_LEN HOST_WIDE_INTs in INPUT into 2 * IN_LEN
+   HOST_HALF_WIDE_INTs of RESULT.  The rest of RESULT is filled by
+   uncompressing the top bit of INPUT[IN_LEN - 1].  */
+
+static void
+wi_unpack (unsigned HOST_HALF_WIDE_INT *result, 
+	   const unsigned HOST_WIDE_INT *input,
+	   int in_len, int out_len)
+{
+  int i;
+  int j = 0;
+  HOST_WIDE_INT mask;
+
+  for (i = 0; i <in_len; i++)
+    {
+      result[j++] = input[i];
+      result[j++] = input[i] >> HOST_BITS_PER_HALF_WIDE_INT;
+    }
+  mask = SIGN_MASK (input[in_len - 1]);
+  mask &= HALF_INT_MASK;
+
+  /* Smear the sign bit.  */
+  while (j < out_len)
+    result[j++] = mask;
+}
+
+/* The inverse of wi_unpack.  IN_LEN is the the number of input
+   blocks.  The number of output blocks will be half this amount.  */
+
+static void
+wi_pack (unsigned HOST_WIDE_INT *result, 
+	 const unsigned HOST_HALF_WIDE_INT *input, 
+	 int in_len)
+{
+  int i = 0;
+  int j = 0;
+
+  while (i < in_len - 2)
+    {
+      result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+	| ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+      i += 2;
+    }
+
+  /* Handle the case where in_len is odd.   For this we zero extend.  */
+  if (i & 1)
+    result[j++] = (unsigned HOST_WIDE_INT)input[i];
+  else
+    result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+      | ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+}
+
+/* Return an integer that is the exact log2 of THIS.  */
+
+wide_int
+wide_int::exact_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  wide_int count;
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec)
+	v = zext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = wide_int::from_shwi (::exact_log2 (v), precision);
+    }
+  else
+    {
+      count = ctz ();
+      if (clz () + count + 1 == precision)
+	result = count;
+      else
+	result = wide_int::from_shwi (-1, precision);
+    }
+  return result;
+}
+
+/* Return an integer that is the floor log2 of THIS.  */
+
+wide_int
+wide_int::floor_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec)
+	v = zext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = wide_int::from_shwi (::floor_log2 (v), precision);
+    }
+  else
+    result = wide_int::from_shwi (precision, precision) - 1 - clz ();
+  return result;
+}
+
+
+/* Multiply Op1 by Op2.  If HIGH is set, only the upper half of the
+   result is returned.  If FULL is set, the entire result is returned
+   in a mode that is twice the width of the inputs.  However, that
+   mode needs to exist if the value is to be usable.  Clients that use
+   FULL need to check for this.
+
+   If HIGH or FULL are not setm throw away the upper half after the check
+   is made to see if it overflows.  Unfortunately there is no better
+   way to check for overflow than to do this.  OVERFLOW is assumed to
+   be sticky so it should be initialized.  SGN controls the signess
+   and is used to check overflow or if HIGH or FULL is set.  */
+
+wide_int
+wide_int::mul_internal (bool high, bool full, 
+			const wide_int *op1, 
+			const HOST_WIDE_INT *op2, unsigned int op2len,
+			wide_int::SignOp sgn,  bool *overflow, 
+			bool needs_overflow)
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1, k, t;
+  unsigned int i;
+  unsigned int j;
+  unsigned int prec = op1->get_precision ();
+  unsigned int blocks_needed = BLOCKS_NEEDED (prec);
+  unsigned int half_blocks_needed = blocks_needed * 2;
+  /* The sizes here are scaled to support a 2x largest mode by 2x
+     largest mode yielding a 4x largest mode result.  This is what is
+     needed by vpn.  */
+
+  unsigned HOST_HALF_WIDE_INT 
+    u[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT 
+    v[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  /* The '2' in 'R' is because we are internally doing a full
+     multiply.  */
+  unsigned HOST_HALF_WIDE_INT 
+    r[2 * 2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1;
+
+  /* If the top level routine did not really pass in an overflow, then
+     just make sure that we never attempt to set it.  */
+  if (overflow == 0)
+    needs_overflow = false;
+  result.precision = op1->precision;
+
+  if (high || full || needs_overflow)
+    {
+      /* If we need to check for overflow, we can only do half wide
+	 multiplies quickly because we need to look at the top bits to
+	 check for the overflow.  */
+      if (prec <= HOST_BITS_PER_HALF_WIDE_INT)
+	{
+	  HOST_WIDE_INT t, r;
+	  result.len = 1;
+	  o0 = op1->elt (0);
+	  o1 = op2[0];
+	  r = o0 * o1;
+	  /* Signed shift down will leave 0 or -1 if there was no
+	     overflow for signed or 0 for unsigned.  */
+	  t = SIGN_MASK (r);
+	  if (needs_overflow)
+	    {
+	      if (sgn == wide_int::SIGNED)
+		{
+		  if (t != (HOST_WIDE_INT)-1 && t != 0)
+		    *overflow = true;
+		}
+	      else
+		{
+		  if (t != 0)
+		    *overflow = true;
+		}
+	    }
+	  if (full)
+	    {
+	      result.val[0] = sext_hwi (r, prec * 2);
+	      result.precision = op1->precision * 2;
+	    }
+	  else if (high)
+	    result.val[0] = r >> prec;
+	  else
+	    result.val[0] = sext_hwi (r, prec);
+	  return result;
+	}
+    }
+
+  wi_unpack (u, (const unsigned HOST_WIDE_INT*)op1->val, op1->len,
+	     half_blocks_needed);
+  wi_unpack (v, (const unsigned HOST_WIDE_INT*)op2, op2len,
+	     half_blocks_needed);
+
+  /* The 2 is for a full mult.  */
+  memset (r, 0, half_blocks_needed * 2 
+	  * HOST_BITS_PER_HALF_WIDE_INT / BITS_PER_UNIT);
+
+  for (j = 0; j < half_blocks_needed; j++)
+    {
+      k = 0;
+      for (i = 0; i < half_blocks_needed; i++)
+	{
+	  t = ((unsigned HOST_WIDE_INT)u[i] * (unsigned HOST_WIDE_INT)v[j]
+	       + r[i + j] + k);
+	  r[i + j] = t & HALF_INT_MASK;
+	  k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	}
+      r[j + half_blocks_needed] = k;
+    }
+
+  /* We did unsigned math above.  For signed we must adjust the
+     product (assuming we need to see that).  */
+  if (sgn == wide_int::SIGNED && (full || high || needs_overflow))
+    {
+      unsigned HOST_WIDE_INT b;
+      if ((*op1).neg_p ())
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)v[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+      if (op2[op2len-1] < 0)
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)u[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+    }
+
+  if (needs_overflow)
+    {
+      HOST_WIDE_INT top;
+
+      /* For unsigned, overflow is true if any of the top bits are set.
+	 For signed, overflow is true if any of the top bits are not equal
+	 to the sign bit.  */
+      if (sgn == wide_int::UNSIGNED)
+	top = 0;
+      else
+	{
+	  top = r[(half_blocks_needed) - 1];
+	  top = SIGN_MASK (top << (HOST_BITS_PER_WIDE_INT / 2));
+	  top &= mask;
+	}
+      
+      for (i = half_blocks_needed; i < half_blocks_needed * 2; i++)
+	if (((HOST_WIDE_INT)(r[i] & mask)) != top)
+	  *overflow = true; 
+    }
+
+  if (full)
+    {
+      /* compute [2prec] <- [prec] * [prec] */
+      wi_pack ((unsigned HOST_WIDE_INT*)result.val, r, 2 * half_blocks_needed);
+      result.len = blocks_needed * 2;
+      result.precision = op1->precision * 2;
+    }
+  else if (high)
+    {
+      /* compute [prec] <- ([prec] * [prec]) >> [prec] */
+      wi_pack ((unsigned HOST_WIDE_INT*)&result.val [blocks_needed >> 1],
+	       r, half_blocks_needed);
+      result.len = blocks_needed;
+    }
+  else
+    {
+      /* compute [prec] <- ([prec] * [prec]) && ((1 << [prec]) - 1) */
+      wi_pack ((unsigned HOST_WIDE_INT*)result.val, r, half_blocks_needed);
+      result.len = blocks_needed;
+    }
+      
+  result.canonize ();
+  return result;
+}
+
+/* Compute the parity of THIS.  */
+
+wide_int
+wide_int::parity () const
+{
+  wide_int count = popcount ();
+  return count & 1;
+}
+
+/* Compute the population count of THIS.  */
+
+wide_int
+wide_int::popcount () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = popcount_hwi (v);
+      start = len - 2;
+    }
+  else
+    {
+      if (sign_mask ())
+	count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      else
+	count = 0;
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = val[i];
+      count += popcount_hwi (v);
+    }
+  return wide_int::from_shwi (count, precision);
+}
+
+/* Subtract of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::sub_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the borrow in of the first element at 1.  */
+  unsigned HOST_WIDE_INT borrow = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.precision = precision;
+  result.len = MAX (len, op1len);
+  mask0 = sign_mask ();
+  mask1 = SIGN_MASK (op1[op1len - 1]);
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1len ? (unsigned HOST_WIDE_INT)op1[i] : mask1;
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      borrow = o0 < o1;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 - mask1 - borrow;
+      result.len++;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/* Subtract of THIS and OP1 with overflow checking.  If the result
+   overflows within the precision, set OVERFLOW.  OVERFLOW is assumed
+   to be sticky so it should be initialized.  SGN controls if signed or
+   unsigned overflow is checked.  */
+
+wide_int
+wide_int::sub (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0 = 0;
+  unsigned HOST_WIDE_INT o1 = 0;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT borrow = 0;
+  unsigned HOST_WIDE_INT old_borrow = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  int i, small_prec;
+
+  gcc_checking_assert (precision == op1.precision);
+
+  result.precision = precision;
+  result.len = MAX (len, op1.len);
+  mask0 = sign_mask ();
+  mask1 = op1.sign_mask ();
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < len; i++)
+    {
+      o0 = val[i];
+      o1 = op1.val[i];
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  /* Uncompress the rest.  */
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = val[i];
+      o1 = mask1;
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  for (i = op1.len; i < len; i++)
+    {
+      o0 = mask0;
+      o1 = op1.val[i];
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      old_borrow = borrow;
+      borrow = o0 < o1;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 - mask1 - borrow;
+      result.len++;
+      /* If we were short, we could not have overflowed.  */
+    }
+  else
+    {
+      small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+      if (small_prec == 0)
+	{
+	  if (sgn == wide_int::SIGNED)
+	    {
+	      if (((x ^ o0) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
+		*overflow = true;
+	    }
+	  else if (old_borrow)
+	    {
+	      if ((~o0) <= o1)
+		*overflow = true;
+	    }
+	  else
+	    {
+	      if ((~o0) < o1)
+		*overflow = true;
+	    }
+	}
+      else
+	{
+	  if (sgn == wide_int::UNSIGNED)
+	    {
+	      /* The caveat for unsigned is to get rid of the bits above
+		 the precision before doing the addition.  To check the
+		 overflow, clear these bits and then redo the last
+		 addition.  If there are any non zero bits above the prec,
+		 we overflowed. */
+	      o0 = zext_hwi (o0, small_prec);
+	      o1 = zext_hwi (o1, small_prec);
+	      x = o0 - o1 - old_borrow;
+	      if (x >> small_prec)
+		*overflow = true;
+	    }
+	  else 
+	    {
+	      /* Overflow in this case is easy since we can see bits beyond
+		 the precision.  If the value computed is not the sign
+		 extended value, then we have overflow.  */
+	      unsigned HOST_WIDE_INT y = sext_hwi (x, small_prec);
+	      if (x != y)
+		*overflow = true;
+	    }
+	}
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/*
+ * Division and Mod
+ */
+
+/* Compute B_QUOTIENT and B_REMAINDER from B_DIVIDEND/B_DIVISOR.  The
+   algorithm is a small modification of the algorithm in Hacker's
+   Delight by Warren, which itself is a small modification of Knuth's
+   algorithm.  M is the number of significant elements of U however
+   there needs to be at least one extra element of B_DIVIDEND
+   allocated, N is the number of elements of B_DIVISOR.  */
+
+void
+wide_int::divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+			     unsigned HOST_HALF_WIDE_INT *b_remainder,
+			     unsigned HOST_HALF_WIDE_INT *b_dividend, 
+			     unsigned HOST_HALF_WIDE_INT *b_divisor, 
+			     int m, int n)
+{
+  /* The "digits" are a HOST_HALF_WIDE_INT which the size of half of a
+     HOST_WIDE_INT and stored in the lower bits of each word.  This
+     algorithm should work properly on both 32 and 64 bit
+     machines.  */
+  unsigned HOST_WIDE_INT b
+    = (unsigned HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT;
+  unsigned HOST_WIDE_INT qhat;   /* Estimate of quotient digit.  */
+  unsigned HOST_WIDE_INT rhat;   /* A remainder.  */
+  unsigned HOST_WIDE_INT p;      /* Product of two digits.  */
+  HOST_WIDE_INT s, i, j, t, k;
+
+  /* Single digit divisor.  */
+  if (n == 1)
+    {
+      k = 0;
+      for (j = m - 1; j >= 0; j--)
+	{
+	  b_quotient[j] = (k * b + b_dividend[j])/b_divisor[0];
+	  k = ((k * b + b_dividend[j])
+	       - ((unsigned HOST_WIDE_INT)b_quotient[j]
+		  * (unsigned HOST_WIDE_INT)b_divisor[0]));
+	}
+      b_remainder[0] = k;
+      return;
+    }
+
+  s = clz_hwi (b_divisor[n-1]) - HOST_BITS_PER_HALF_WIDE_INT; /* CHECK clz */
+
+  /* Normalize B_DIVIDEND and B_DIVISOR.  Unlike the published
+     algorithm, we can overwrite b_dividend and b_divisor, so we do
+     that.  */
+  for (i = n - 1; i > 0; i--)
+    b_divisor[i] = (b_divisor[i] << s)
+      | (b_divisor[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_divisor[0] = b_divisor[0] << s;
+
+  b_dividend[m] = b_dividend[m-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s);
+  for (i = m - 1; i > 0; i--)
+    b_dividend[i] = (b_dividend[i] << s)
+      | (b_dividend[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_dividend[0] = b_dividend[0] << s;
+
+  /* Main loop.  */
+  for (j = m - n; j >= 0; j--)
+    {
+      qhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) / b_divisor[n-1];
+      rhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) - qhat * b_divisor[n-1];
+    again:
+      if (qhat >= b || qhat * b_divisor[n-2] > b * rhat + b_dividend[j+n-2])
+	{
+	  qhat -= 1;
+	  rhat += b_divisor[n-1];
+	  if (rhat < b)
+	    goto again;
+	}
+
+      /* Multiply and subtract.  */
+      k = 0;
+      for (i = 0; i < n; i++)
+	{
+	  p = qhat * b_divisor[i];
+	  t = b_dividend[i+j] - k - (p & HALF_INT_MASK);
+	  b_dividend[i + j] = t;
+	  k = ((p >> HOST_BITS_PER_HALF_WIDE_INT)
+	       - (t >> HOST_BITS_PER_HALF_WIDE_INT));
+	}
+      t = b_dividend[j+n] - k;
+      b_dividend[j+n] = t;
+
+      b_quotient[j] = qhat;
+      if (t < 0)
+	{
+	  b_quotient[j] -= 1;
+	  k = 0;
+	  for (i = 0; i < n; i++)
+	    {
+	      t = (HOST_WIDE_INT)b_dividend[i+j] + b_divisor[i] + k;
+	      b_dividend[i+j] = t;
+	      k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	    }
+	  b_dividend[j+n] += k;
+	}
+    }
+  for (i = 0; i < n; i++)
+    b_remainder[i] = (b_dividend[i] >> s) 
+      | (b_dividend[i+1] << (HOST_BITS_PER_HALF_WIDE_INT - s));
+}
+
+
+/* Do a truncating divide DIVISOR into DIVIDEND.  The result is the
+   same size as the operands.  SIGN is either wide_int::SIGNED or
+   wide_int::UNSIGNED.  */
+
+wide_int
+wide_int::divmod_internal (bool compute_quotient, 
+			   const wide_int *dividend, 
+			   const HOST_WIDE_INT *divisor,
+			   unsigned int divisorlen,
+			   wide_int::SignOp sgn, wide_int *remainder,
+			   bool compute_remainder, 
+			   bool *oflow)
+{
+  wide_int quotient, u0, u1;
+  unsigned int prec = dividend->get_precision();
+  int blocks_needed = 2 * BLOCKS_NEEDED (prec);
+  /* The '2' in the next 4 vars are because they are built on half
+     sized wide ints.  */
+  unsigned HOST_HALF_WIDE_INT 
+    b_quotient[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_remainder[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_dividend[(MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT) + 1];
+  unsigned HOST_HALF_WIDE_INT
+    b_divisor[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  int m, n;
+  bool dividend_neg = false;
+  bool divisor_neg = false;
+  bool overflow = false;
+
+  if (divisor[0] == 0 && divisorlen == 1)
+    overflow = true;
+
+  /* The smallest signed number / -1 causes overflow.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      wide_int t = wide_int::set_bit_in_zero (prec - 1, prec);
+      if (*dividend == t && divisor[0] == -1 && divisorlen == 1)
+	overflow = true;
+    }
+
+  quotient.precision = prec;
+  remainder->precision = prec;
+
+  /* If overflow is set, just get out.  There will only be grief by
+     continuing.  */
+  if (overflow)
+    {
+      if (compute_remainder)
+	{
+	  remainder->len = 1;
+	  remainder->val[0] = 0;
+	}
+      if (oflow != 0)
+	*oflow = true;
+      return wide_int::zero (prec);
+    }
+
+  /* Do it on the host if you can.  */
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      quotient.len = 1;
+      remainder->len = 1;
+      if (sgn == wide_int::SIGNED)
+	{
+	  quotient.val[0] 
+	    = sext_hwi (dividend->val[0] / divisor[0], prec);
+	  remainder->val[0] 
+	    = sext_hwi (dividend->val[0] % divisor[0], prec);
+	}
+      else
+	{
+	  unsigned HOST_WIDE_INT o0 = dividend->val[0];
+	  unsigned HOST_WIDE_INT o1 = divisor[0];
+
+	  if (prec < HOST_BITS_PER_WIDE_INT)
+	    {
+	      o0 = zext_hwi (o0, prec);
+	      o1 = zext_hwi (o1, prec);
+	    }
+	  quotient.val[0] = sext_hwi (o0 / o1, prec);
+	  remainder->val[0] = sext_hwi (o0 % o1, prec);
+	}
+      return quotient;
+    }
+
+  /* Make the divisor and divident positive and remember what we
+     did.  */
+  if (sgn == wide_int::SIGNED)
+    {
+      if (dividend->sign_mask ())
+	{
+	  u0 = dividend->neg ();
+	  dividend = &u0;
+	  dividend_neg = true;
+	}
+      if (divisor[divisorlen - 1] < 0)
+	{
+	  u1 = wide_int::zero (dividend->precision).sub_large (divisor, divisorlen);
+	  divisor = u1.val;
+	  divisorlen = u1.len;
+	  divisor_neg = true;
+	}
+    }
+
+  wi_unpack (b_dividend, (const unsigned HOST_WIDE_INT*)dividend->val,
+	     dividend->len, blocks_needed);
+  wi_unpack (b_divisor, (const unsigned HOST_WIDE_INT*)divisor, 
+	     divisorlen, blocks_needed);
+
+  if (dividend->sign_mask ())
+    m = blocks_needed;
+  else
+    m = 2 * dividend->get_len ();
+
+  if (SIGN_MASK (divisor[divisorlen - 1]))
+    n = blocks_needed;
+  else
+    n = 2 * divisorlen;
+
+  /* It is known that the top input block to the divisor is non zero,
+     but when this block is split into two half blocks, it may be that
+     the top half block is zero.  Skip over this half block.  */
+  if (b_divisor[n - 1] == 0)
+    n--;
+
+  divmod_internal_2 (b_quotient, b_remainder, b_dividend, b_divisor, m, n);
+
+  if (compute_quotient)
+    {
+      wi_pack ((unsigned HOST_WIDE_INT*)quotient.val, b_quotient, m);
+      quotient.len = m / 2;
+      quotient.canonize ();
+      /* The quotient is neg if exactly one of the divisor or dividend is
+	 neg.  */
+      if (dividend_neg != divisor_neg)
+	quotient = quotient.neg ();
+    }
+  else
+    quotient = wide_int::zero (dividend->precision);
+
+  if (compute_remainder)
+    {
+      wi_pack ((unsigned HOST_WIDE_INT*)remainder->val, b_remainder, n);
+      if (n & 1)
+	n++;
+      remainder->len = n / 2;
+      (*remainder).canonize ();
+      /* The remainder is always the same sign as the dividend.  */
+      if (dividend_neg)
+	*remainder = (*remainder).neg ();
+    }
+  else
+    *remainder = wide_int::zero (dividend->precision);
+  return quotient;
+}
+
+
+/*
+ * Shifting, rotating and extraction.
+ */
+
+/* Extract WIDTH bits from THIS starting at OFFSET.  The result is
+   assumed to fit in a HOST_WIDE_INT.  This function is safe in that
+   it can properly access elements that may not be explicitly
+   represented.  */
+
+HOST_WIDE_INT
+wide_int::extract_to_hwi (int offset, int width) const
+{
+  int start_elt, end_elt, shift;
+  HOST_WIDE_INT x;
+
+  /* Get rid of the easy cases first.   */
+  if (offset >= len * HOST_BITS_PER_WIDE_INT)
+    return sign_mask ();
+  if (offset + width <= 0)
+    return 0;
+
+  shift = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset < 0)
+    {
+      start_elt = -1;
+      end_elt = 0;
+      x = 0;
+    }
+  else
+    {
+      start_elt = offset / HOST_BITS_PER_WIDE_INT;
+      end_elt = (offset + width - 1) / HOST_BITS_PER_WIDE_INT;
+      x = start_elt >= len 
+	? sign_mask ()
+	: (unsigned HOST_WIDE_INT)val[start_elt] >> shift;
+    }
+
+  if (start_elt != end_elt)
+    {
+      HOST_WIDE_INT y = end_elt == len
+	? sign_mask () : val[end_elt];
+
+      x |= y << (HOST_BITS_PER_WIDE_INT - shift);
+    }
+
+  if (width != HOST_BITS_PER_WIDE_INT)
+    x &= ((HOST_WIDE_INT)1 << width) - 1;
+
+  return x;
+}
+
+
+/* Left shift THIS by CNT.  See the definition of Op.TRUNC for how to
+   set Z.  Since this is used internally, it has the ability to
+   specify the BISIZE and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+wide_int
+wide_int::lshift_large (unsigned int cnt, unsigned int res_prec) const
+{
+  wide_int result;
+  unsigned int i;
+
+  result.precision = res_prec;
+
+  if (cnt >= res_prec)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+      return result;
+    }
+
+  for (i = 0; i < res_prec; i += HOST_BITS_PER_WIDE_INT)
+    result.val[i / HOST_BITS_PER_WIDE_INT]
+      = extract_to_hwi (i - cnt, HOST_BITS_PER_WIDE_INT);
+
+  result.len = BLOCKS_NEEDED (res_prec);
+  result.canonize ();
+
+  return result;
+}
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set Z.  */
+
+wide_int
+wide_int::rshiftu_large (unsigned int cnt) const
+{
+  wide_int result;
+  int stop_block, offset, i;
+
+  result.precision = precision;
+
+  if (cnt >= precision)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  offset = (precision - cnt) & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset)
+    result.val[stop_block - 1] = zext_hwi (result.val[stop_block - 1], offset);
+  else
+    /* The top block had a 1 at the top position so it will decompress
+       wrong unless a zero block is added.  This only works because we
+       know the shift was greater than 0.  */
+    if (result.val[stop_block - 1] < 0)
+      result.val[result.len++] = 0;
+  return result;
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set Z.  */
+
+wide_int
+wide_int::rshifts_large (unsigned int cnt) const
+{
+  wide_int result;
+  int stop_block, i;
+
+  result.precision = precision;
+
+  if (cnt >= precision)
+    {
+      HOST_WIDE_INT m = sign_mask ();
+      result.val[0] = m;
+      result.len = 1;
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  /* No need to sign extend the last block, since it extract_to_hwi
+     already did that.  */
+  return result;
+}
+
+/*
+ * Private utilities.
+ */
+/* Decompress THIS for at least TARGET bits into a result with
+   precision PREC.  */
+
+wide_int
+wide_int::decompress (unsigned int target, unsigned int prec) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (target);
+  HOST_WIDE_INT mask;
+  int len, i;
+
+  result.precision = prec;
+  result.len = blocks_needed;
+
+  for (i = 0; i < this->len; i++)
+    result.val[i] = val[i];
+
+  len = this->len;
+
+  if (target > result.precision)
+    return result;
+
+  /* The extension that we are doing here is not sign extension, it is
+     decompression.  */
+  mask = sign_mask ();
+  while (len < blocks_needed)
+    result.val[len++] = mask;
+
+  return result;
+}
+
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
new file mode 100644
index 0000000..7fec321
--- /dev/null
+++ b/gcc/wide-int.h
@@ -0,0 +1,2464 @@
+/* Operations with very long integers.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef WIDE_INT_H
+#define WIDE_INT_H
+
+/* A wide integer is currently represented as a vector of
+   HOST_WIDE_INTs.  The vector contains enough elements to hold a
+   value of MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT which is
+   a derived for each host target combination.  The values are stored
+   in the vector with the least signicant HOST_BITS_PER_WIDE_INT bits
+   of the value stored in element 0.
+
+   A wide_int contains three fields: the vector (VAL), precision and a
+   length, (LEN).  The length is the number of HWIs needed to
+   represent the value.
+
+   Since most integers used in a compiler are small values, it is
+   generally profitable to use a representation of the value that is
+   shorter than the modes precision.  LEN is used to indicate the
+   number of elements of the vector that are in use.  When LEN *
+   HOST_BITS_PER_WIDE_INT < the precision, the value has been
+   compressed.  The values of the elements of the vector greater than
+   LEN - 1. are all equal to the highest order bit of LEN.
+
+   The representation does not contain any information inherant about
+   signedness of the represented value, so it can be used to represent
+   both signed and unsigned numbers.   For operations where the results
+   depend on signedness (division, comparisons), the signedness must
+   be specified separately.  For operations where the signness
+   matters, one of the operands to the operation specifies either
+   wide_int::SIGNED or wide_int::UNSIGNED.
+
+   The numbers are stored as sign entended numbers as a means of
+   compression.  Leading HOST_WIDE_INTS that contain strings of either
+   -1 or 0 are removed as long as they can be reconstructed from the
+   top bit that is being represented.
+
+   All constructors for wide_int take either a precision, an enum
+   machine_mode or tree_type.  */
+
+
+#ifndef GENERATOR_FILE
+#include "tree.h"
+#include "system.h"
+#include "hwint.h"
+#include "options.h"
+#include "tm.h"
+#include "insn-modes.h"
+#include "machmode.h"
+#include "double-int.h"
+#include <gmp.h>
+#include "dumpfile.h"
+#include "real.h"
+
+#define WIDE_INT_MAX_ELTS \
+  ((4 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+
+class wide_int {
+  /* Internal representation.  */
+  
+  /* VAL is set to a size that is capable of computing a full
+     multiplication on the largest mode that is represented on the
+     target.  The full multiplication is use by tree-vrp.  tree-vpn
+     currently does a 2x largest mode by 2x largest mode yielding a 4x
+     largest mode result.  If operations are added that require larger
+     buffers, then VAL needs to be changed.  */
+  HOST_WIDE_INT val[WIDE_INT_MAX_ELTS];
+  unsigned short len;
+  unsigned int precision;
+
+ public:
+  enum ShiftOp {
+    NONE,
+    /* There are two uses for the wide-int shifting functions.  The
+       first use is as an emulation of the target hardware.  The
+       second use is as service routines for other optimizations.  The
+       first case needs to be identified by passing TRUNC as the value
+       of ShiftOp so that shift amount is properly handled according to the
+       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
+       amount is always truncated by the bytesize of the mode of
+       THIS.  */
+    TRUNC
+  };
+
+  enum SignOp {
+    /* Many of the math functions produce different results depending
+       on if they are SIGNED or UNSIGNED.  In general, there are two
+       different functions, whose names are prefixed with an 'S" and
+       or an 'U'.  However, for some math functions there is also a
+       routine that does not have the prefix and takes an SignOp
+       parameter of SIGNED or UNSIGNED.  */
+    SIGNED,
+    UNSIGNED
+  };
+
+  /* Conversions.  */
+
+  static wide_int from_shwi (HOST_WIDE_INT op0, 
+			     unsigned int precision, bool *overflow = 0);
+  static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+			     unsigned int precision, bool *overflow = 0);
+
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type, 
+				   bool *overflow = 0);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+				    bool *overflow = 0);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+				    enum machine_mode mode, 
+				    bool *overflow = 0);
+  static wide_int from_array (const HOST_WIDE_INT* op0,
+			      unsigned int len, 
+			      unsigned int precision, bool need_canon = true); 
+  inline static wide_int from_array (const HOST_WIDE_INT* op0,
+				     unsigned int len,
+				     enum machine_mode mode);
+  inline static wide_int from_array (const HOST_WIDE_INT* op0,
+				     unsigned int len,
+				     const_tree type);
+
+  static wide_int from_double_int (double_int, 
+				   unsigned int precision);
+  inline static wide_int from_double_int (double_int, enum machine_mode);
+  static wide_int from_tree (const_tree);
+  static wide_int from_rtx (const_rtx, enum machine_mode);
+  static wide_int from_buffer (const unsigned char*, int);
+
+  inline HOST_WIDE_INT to_shwi (unsigned int prec = 0) const;
+  inline unsigned HOST_WIDE_INT to_uhwi (unsigned int prec = 0) const;
+
+  /* Largest and smallest values that are represented in modes or precisions.  */
+
+  static wide_int max_value (unsigned int prec, 
+			     unsigned int precision, SignOp sgn);
+  inline static wide_int max_value (unsigned int precision, SignOp sgn);
+  inline static wide_int max_value (const_tree type);
+  inline static wide_int max_value (enum machine_mode mode, SignOp sgn);
+  
+  static wide_int min_value (unsigned int prec, 
+			     unsigned int precision, SignOp sgn);
+  inline static wide_int min_value (unsigned int precision, SignOp sgn);
+  inline static wide_int min_value (const_tree type);
+  inline static wide_int min_value (enum machine_mode mode, SignOp sgn);
+  
+  /* Small constants */
+
+  inline static wide_int minus_one (unsigned int prec);
+  inline static wide_int zero (unsigned int prec);
+  inline static wide_int one (unsigned int prec);
+  inline static wide_int two (unsigned int prec);
+
+  /* Accessors.  */
+
+  inline unsigned short get_len () const;
+  inline unsigned int get_precision () const;
+  inline HOST_WIDE_INT elt (unsigned int i) const;
+
+  /* Printing functions.  */
+
+  void print_dec (char *buf, SignOp sgn) const;
+  void print_dec (FILE *file, SignOp sgn) const;
+  void print_decs (char *buf) const;
+  void print_decs (FILE *file) const;
+  void print_decu (char *buf) const;
+  void print_decu (FILE *file) const;
+  void print_hex (char *buf) const;
+  void print_hex (FILE *file) const;
+
+  /* Comparative functions.  */
+
+  inline bool minus_one_p () const;
+  inline bool zero_p () const;
+  inline bool one_p () const;
+  inline bool neg_p () const;
+
+  template <typename T>
+    inline bool operator == (T c) const;
+  
+  template <typename T>
+    inline bool operator != (T c) const;
+  
+  template <typename T>
+    inline bool gt_p (T c, SignOp sgn) const;
+  template <typename T>
+    inline bool gts_p (T c) const;
+  template <typename T>
+    inline bool gtu_p (T c) const;
+  
+  template <typename T>
+    inline bool lt_p (T c, SignOp sgn) const;
+  template <typename T>
+    inline bool lts_p (T c) const;
+  template <typename T>
+    inline bool ltu_p (T c) const;
+  
+  template <typename T>
+    inline int cmp (T c, SignOp sgn) const;
+  template <typename T>
+    inline int cmps (T c) const;
+  template <typename T>
+    inline int cmpu (T c) const;
+  
+  bool only_sign_bit_p (unsigned int prec) const;
+  inline bool only_sign_bit_p () const;
+  inline bool fits_uhwi_p () const;
+  inline bool fits_shwi_p () const;
+  bool fits_to_tree_p (const_tree type) const;
+  bool fits_u_p (unsigned int prec) const;
+  bool fits_s_p (unsigned int prec) const;
+
+  /* Min and max */
+
+  template <typename T>
+    inline wide_int min (T c, SignOp sgn) const;
+    inline wide_int min (const wide_int &op1, SignOp sgn) const;
+  template <typename T>
+    inline wide_int max (T c, SignOp sgn) const;
+    inline wide_int max (const wide_int &op1, SignOp sgn) const;
+  template <typename T>
+    inline wide_int smin (T c) const;
+    inline wide_int smin (const wide_int &op1) const;
+  template <typename T>
+    inline wide_int smax (T c) const;
+    inline wide_int smax (const wide_int &op1) const;
+  template <typename T>
+    inline wide_int umin (T c) const;
+    inline wide_int umin (const wide_int &op1) const;
+  template <typename T>
+    inline wide_int umax (T c) const;
+    inline wide_int umax (const wide_int &op1) const;
+
+  /* Extension, these do not change the precision.  */
+
+  inline wide_int ext (unsigned int offset, SignOp sgn) const;
+  wide_int sext (unsigned int offset) const;
+  wide_int zext (unsigned int offset) const;
+
+  /* Make a fast copy.  */
+
+  wide_int copy () const;
+
+  /* These change the underlying precision.  */
+  
+  wide_int force_to_size (unsigned int precision, SignOp sgn) const;
+  inline wide_int force_to_size (enum machine_mode mode, SignOp sgn) const;
+  inline wide_int force_to_size (const_tree type) const;
+  inline wide_int force_to_size (const_tree type, SignOp sgn) const;
+
+  inline wide_int sforce_to_size (enum machine_mode mode) const;
+  inline wide_int sforce_to_size (const_tree type) const;
+  inline wide_int zforce_to_size (enum machine_mode mode) const;
+  inline wide_int zforce_to_size (const_tree type) const;
+
+  /* Masking, and Insertion  */
+
+  wide_int set_bit (unsigned int bitpos) const;
+  static wide_int set_bit_in_zero (unsigned int bitpos, unsigned int prec);
+  inline static wide_int set_bit_in_zero (unsigned int, 
+					  enum machine_mode mode);
+  inline static wide_int set_bit_in_zero (unsigned int, const_tree type);
+  wide_int insert (const wide_int &op0, unsigned int offset,
+		   unsigned int width) const;
+
+  wide_int bswap () const;
+
+  static wide_int mask (unsigned int start, bool negate, 
+			unsigned int prec);
+  inline static wide_int mask (unsigned int start, bool negate, 
+			       enum machine_mode mode);
+  inline static wide_int mask (unsigned int start, bool negate,
+			       const_tree type);
+
+  static wide_int shifted_mask (unsigned int start, unsigned int width,
+				bool negate, unsigned int prec);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, enum machine_mode mode);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, const_tree type);
+
+  inline HOST_WIDE_INT sign_mask () const;
+
+  /* Logicals */
+
+  template <typename T>
+    inline wide_int operator & (T c) const;
+  template <typename T>
+    inline wide_int and_not (T c) const;
+  inline wide_int operator ~ () const;
+  template <typename T>
+    inline wide_int operator | (T c) const;
+  template <typename T>
+    inline wide_int or_not (T c) const;
+  template <typename T>
+    inline wide_int operator ^ (T c) const;
+  
+  /* Arithmetic operation functions, alpha sorted.  */
+  
+  wide_int abs () const;
+  template <typename T>
+    inline wide_int operator + (T c) const;
+  wide_int add (const wide_int &x, SignOp sgn, bool *overflow) const;
+  
+  wide_int clz () const;
+  wide_int clrsb () const;
+  wide_int ctz () const;
+  wide_int exact_log2 () const;
+  wide_int floor_log2 () const;
+  wide_int ffs () const;
+  
+  template <typename T>
+    inline wide_int operator * (T c) const;
+  template <typename T>
+    inline wide_int mul (T c, SignOp sgn, bool *overflow) const;
+  template <typename T>
+    inline wide_int smul (T c, bool *overflow) const;
+  template <typename T>
+    inline wide_int umul (T c, bool *overflow) const;
+  template <typename T>
+    inline wide_int mul_full (T c, SignOp sgn) const;
+  template <typename T>
+    inline wide_int smul_full (T c) const;
+  template <typename T>
+    inline wide_int umul_full (T c) const;
+  template <typename T>
+    inline wide_int mul_high (T c, SignOp sgn) const;
+  
+  inline wide_int neg () const;
+  inline wide_int neg (bool *overflow) const;
+  
+  wide_int parity () const;
+  wide_int popcount () const;
+  
+  template <typename T>
+    inline wide_int operator - (T c) const;
+  wide_int sub (const wide_int &x, SignOp sgn, bool *overflow) const;
+  
+  /* Divison and mod.  These are the ones that are actually used, but
+     there are a lot of them.  */
+  
+  template <typename T>
+    inline wide_int div_trunc (T c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+    inline wide_int sdiv_trunc (T c) const;
+  template <typename T>
+    inline wide_int udiv_trunc (T c) const;
+  
+  template <typename T>
+    inline wide_int div_floor (T c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+    inline wide_int udiv_floor (T c) const;
+  template <typename T>
+    inline wide_int sdiv_floor (T c) const;
+  template <typename T>
+    inline wide_int div_ceil (T c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+    inline wide_int div_round (T c, SignOp sgn, bool *overflow = 0) const;
+  
+  template <typename T>
+    inline wide_int divmod_trunc (T c, wide_int *mod, SignOp sgn) const;
+  template <typename T>
+    inline wide_int sdivmod_trunc (T c, wide_int *mod) const;
+  template <typename T>
+    inline wide_int udivmod_trunc (T c, wide_int *mod) const;
+  
+  template <typename T>
+    inline wide_int divmod_floor (T c, wide_int *mod, SignOp sgn) const;
+  template <typename T>
+    inline wide_int sdivmod_floor (T c, wide_int *mod) const;
+  
+  template <typename T>
+    inline wide_int mod_trunc (T c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+    inline wide_int smod_trunc (T c) const;
+  template <typename T>
+    inline wide_int umod_trunc (T c) const;
+  
+  template <typename T>
+    inline wide_int mod_floor (T c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+    inline wide_int umod_floor (T c) const;
+  template <typename T>
+    inline wide_int mod_ceil (T c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+    inline wide_int mod_round (T c, SignOp sgn, bool *overflow = 0) const;
+  
+  /* Shifting rotating and extracting.  */
+  HOST_WIDE_INT extract_to_hwi (int offset, int width) const;
+  
+  template <typename T>
+    inline wide_int lshift (T c, unsigned int bitsize = 0,
+			    unsigned int precision = 0,
+			    ShiftOp z = NONE) const;
+
+  template <typename T>
+    inline wide_int lrotate (T c) const;
+  inline wide_int lrotate (unsigned HOST_WIDE_INT y) const;
+
+  template <typename T>
+    inline wide_int rshift (T c, SignOp sgn, 
+			    unsigned int bitsize = 0,
+			    ShiftOp z = NONE) const;
+  template <typename T>
+    inline wide_int rshiftu (T c, unsigned int bitsize = 0,
+			     ShiftOp z = NONE) const;
+  template <typename T>
+    inline wide_int rshifts (T c, unsigned int bitsize = 0,
+			     ShiftOp z = NONE) const;
+
+  template <typename T>
+    inline wide_int rrotate (T c) const;
+    inline wide_int rrotate (unsigned HOST_WIDE_INT y) const;
+
+  static const int DUMP_MAX = (2 * (MAX_BITSIZE_MODE_ANY_INT / 4
+			       + MAX_BITSIZE_MODE_ANY_INT 
+				    / HOST_BITS_PER_WIDE_INT + 32));
+  char *dump (char* buf) const;
+ private:
+
+  /* 
+   * Internal versions that do the work if the values do not fit in a
+   * HWI.
+   */ 
+
+  /* Comparisons */
+  bool eq_p_large (const HOST_WIDE_INT *, unsigned int) const;
+  static bool lts_p_large (const HOST_WIDE_INT *, unsigned int, 
+			   const HOST_WIDE_INT *, unsigned int,
+			   unsigned int);
+  int cmps_large (const HOST_WIDE_INT *, unsigned int) const;
+  static bool ltu_p_large (const HOST_WIDE_INT *, unsigned int, 
+			   const HOST_WIDE_INT *, unsigned int);
+  int cmpu_large (const HOST_WIDE_INT *, unsigned int) const;
+
+  /* Logicals.  */
+  wide_int and_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int and_not_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int or_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int or_not_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int xor_large (const HOST_WIDE_INT *, unsigned int) const;
+
+  /* Arithmetic */
+  wide_int add_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int sub_large (const HOST_WIDE_INT *, unsigned int) const;
+
+  wide_int lshift_large (unsigned int cnt, unsigned int res_prec) const;
+  wide_int rshiftu_large (unsigned int cnt) const;
+  wide_int rshifts_large (unsigned int cnt) const;
+
+  static wide_int
+    mul_internal (bool high, bool full, 
+		  const wide_int *op1, const HOST_WIDE_INT *op2, unsigned int op2len,
+		  wide_int::SignOp sgn,  bool *overflow, bool needs_overflow);
+  static void
+    divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+		       unsigned HOST_HALF_WIDE_INT *b_remainder,
+		       unsigned HOST_HALF_WIDE_INT *b_dividend, 
+		       unsigned HOST_HALF_WIDE_INT *b_divisor, 
+		       int m, int n);
+  static wide_int
+    divmod_internal (bool compute_quotient, 
+		     const wide_int *dividend, const HOST_WIDE_INT *, unsigned int,
+		     wide_int::SignOp sgn, wide_int *remainder,
+		     bool compute_remainder, 
+		     bool *overflow);
+
+
+  /* Private utility routines.  */
+  wide_int decompress (unsigned int target, unsigned int precision) const;
+  void canonize ();
+  static inline int trunc_shift (const HOST_WIDE_INT *cnt, unsigned int len, 
+				 unsigned int bitsize, ShiftOp z);
+
+  /* The following template and its overrides are used for the second
+     operand of binary functions.  They access the value are package
+     it so that the operation can be done.  These have been
+     implemented so that pointer copying is done from the rep of the
+     second operand rather than actual data copying.  This is safe
+     even for garbage collected objects since the value is immediately
+     throw away.  
+
+     The first two templates match all integers.  */
+
+  template <typename T>
+  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int *l, T x)
+  { 
+    s[0] = x;
+    if (~(T)0 < (T)0
+	|| sizeof (T) < sizeof (HOST_WIDE_INT))
+      {
+	*l = 1;
+      }
+    else
+      {
+	s[1] = 0;
+	*l = 2;	  
+      }
+    return s;
+  }
+  
+  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s ATTRIBUTE_UNUSED,
+					int *l, const wide_int &y)
+  {
+    *l = y.len;
+    return y.val;
+  }
+
+  /* This overload may just return the pointer to the value and set
+     the length.  */
+  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int *l, const_tree tcst)
+  {
+    /* This is rather complex now, in the future when the rep for tree
+       cst is changed, it will be just a pointer and len copy.  */
+    tree type = TREE_TYPE (tcst);
+    unsigned int prec = TYPE_PRECISION (type);
+
+    if (prec == HOST_BITS_PER_DOUBLE_INT 
+	&& TYPE_UNSIGNED (type)
+	&& TREE_INT_CST_HIGH (tcst) < 0)
+      {
+	/* Copy the result because it does not fit in two HWIs.  */
+	s[0] = TREE_INT_CST_LOW (tcst);
+	s[1] = TREE_INT_CST_HIGH (tcst);
+	s[2] = 0;
+	*l = 3;
+	return s;
+      }
+    else
+      {
+	if (prec > HOST_BITS_PER_WIDE_INT)
+	  *l = 2;
+	else
+	  {
+	    if (prec == HOST_BITS_PER_WIDE_INT
+		&& TYPE_UNSIGNED (type)
+		&& (HOST_WIDE_INT)TREE_INT_CST_LOW (tcst) < 0)
+	      *l = 2;
+	    else
+	      *l = 1;
+	  }
+	return (const HOST_WIDE_INT*)&TREE_INT_CST_LOW (tcst);
+      }
+  }
+
+  /* There should logically be an overload for rtl here, but it cannot
+     be here because of circular include issues.  It is in rtl.h.  */
+  static inline const HOST_WIDE_INT* to_shwi2 
+    (HOST_WIDE_INT *s ATTRIBUTE_UNUSED, int *l, rtx rcst);
+
+};
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with precision
+   taken from MODE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, enum machine_mode mode)
+{
+  return wide_int::set_bit_in_zero (bitpos, GET_MODE_PRECISION (mode));
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with precision
+   taken from TYPE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, const_tree type)
+{
+
+  return wide_int::set_bit_in_zero (bitpos, TYPE_PRECISION (type));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with precision
+   taken from MODE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, enum machine_mode mode)
+{
+  return wide_int::mask (width, negate, GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with precision
+   taken from TYPE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, const_tree type)
+{
+
+  return wide_int::mask (width, negate, TYPE_PRECISION (type));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the bits
+   above that up to the precision are zeros.  The result is inverted
+   if NEGATE is true.  The result is made with precision taken from
+   MODE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, enum machine_mode mode)
+{
+  return wide_int::shifted_mask (start, width, negate,
+				 GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the bits
+   above that up to the precision are zeros.  The result is inverted
+   if NEGATE is true.  The result is made with precision taken from
+   TYPE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, const_tree type)
+{
+
+  return wide_int::shifted_mask (start, width, negate,
+				 TYPE_PRECISION (type));
+}
+
+/* Produce 0 or -1 that is the smear of the sign bit.  */
+
+HOST_WIDE_INT
+wide_int::sign_mask () const
+{
+  int i = len - 1;
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
+	    >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* VRP appears to be badly broken and this is a very ugly fix.  */
+  if (i >= 0)
+    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
+
+  gcc_unreachable ();
+#if 0
+  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
+#endif
+}
+
+/* Conversions */
+
+/* Convert OP0 into a wide_int with parameters taken from TYPE.  If
+   the value does not fit, set OVERFLOW.  */
+
+wide_int
+wide_int::from_hwi (HOST_WIDE_INT op0, const_tree type, 
+		    bool *overflow)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return wide_int::from_uhwi (op0, prec, overflow);
+  else
+    return wide_int::from_shwi (op0, prec, overflow);
+}
+
+/* Convert signed OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode, 
+		     bool *overflow)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_shwi (op0, prec, overflow);
+}
+
+/* Convert unsigned OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode, 
+		     bool *overflow)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_uhwi (op0, prec, overflow);
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec == 0)
+    prec = precision;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = sext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec == 0)
+    prec = precision;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = zext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+
+/* Convert OP0 of LEN into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT* op0, unsigned int len, 
+		      enum machine_mode mode)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_array (op0, len, prec);
+}
+
+/* Convert OP0 of LEN into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT* op0, unsigned int len, 
+		      const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return wide_int::from_array (op0, len, prec);
+}
+
+/* Convert double_int OP0 into a wide_int with parameters taken from
+   MODE.  */
+
+wide_int
+wide_int::from_double_int (double_int op0, enum machine_mode mode)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_double_int (op0, prec);
+}
+
+/* Min and Max value helpers.  */
+
+/* Produce the largest SGNed number that is represented in PRECISION.
+   The result is represented in PRECISION.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (unsigned int precision, SignOp sgn)
+{
+  return max_value (precision, precision, sgn);
+}
+  
+/* Produce the largest number that is represented in MODE. The
+   precision are taken from mode.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (enum machine_mode mode, SignOp sgn)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+  return max_value (prec, prec, sgn);
+}
+
+/* Produce the largest number that is represented in TYPE. The
+   precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::max_value (const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  return max_value (prec, prec, TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+/* Produce the smallest SGNed number that is represented in PRECISION.
+   The result is represented in PRECISION.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::min_value (unsigned int precision, SignOp sgn)
+{
+  return min_value (precision, precision, sgn);
+}
+  
+/* Produce the smallest number that is represented in MODE. The
+   precision are taken from mode.  SGN must be SIGNED or UNSIGNED.  */
+
+wide_int
+wide_int::min_value (enum machine_mode mode, SignOp sgn)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+  return min_value (prec, prec, sgn);
+}
+
+/* Produce the smallest number that is represented in TYPE. The
+   precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::min_value (const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  return min_value (prec, prec, TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED);
+}
+
+
+/* Small constants.  */
+
+/* Return a wide int of -1 with precision PREC.  */
+
+wide_int
+wide_int::minus_one (unsigned int prec)
+{
+  return wide_int::from_shwi (-1, prec);
+}
+
+/* Return a wide int of 0 with precision PREC.  */
+
+wide_int
+wide_int::zero (unsigned int prec)
+{
+  return wide_int::from_shwi (0, prec);
+}
+
+/* Return a wide int of 1 with precision PREC.  */
+
+wide_int
+wide_int::one (unsigned int prec)
+{
+  return wide_int::from_shwi (1, prec);
+}
+
+/* Return a wide int of 2 with precision PREC.  */
+
+wide_int
+wide_int::two (unsigned int prec)
+{
+  return wide_int::from_shwi (2, prec);
+}
+
+/* Public accessors for the interior of a wide int.  */
+
+/* Get the number of host wide ints actually represented within the
+   wide int.  */
+
+unsigned short
+wide_int::get_len () const
+{
+  return len;
+}
+
+/* Get precision of the value represented within the wide int.  */
+
+unsigned int
+wide_int::get_precision () const
+{
+  return precision;
+}
+
+/* Get a particular element of the wide int.  */
+
+HOST_WIDE_INT
+wide_int::elt (unsigned int i) const
+{
+  return i >= len ? sign_mask () : val[i];
+}
+
+/* Return true if THIS is -1.  */
+
+bool
+wide_int::minus_one_p () const
+{
+  return len == 1 && val[0] == (HOST_WIDE_INT)-1;
+}
+
+/* Return true if THIS is 0.  */
+
+bool
+wide_int::zero_p () const
+{
+  return len == 1 && val[0] == 0;
+}
+
+/* Return true if THIS is 1.  */
+
+bool
+wide_int::one_p () const
+{
+  return len == 1 && val[0] == 1;
+}
+
+/* Return true if THIS is negative.  */
+
+bool
+wide_int::neg_p () const
+{
+  return sign_mask () != 0;
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently signed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+template <typename T>
+bool
+wide_int::operator == (T c) const
+{
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << precision) - 1;
+      result = (val[0] & mask) == (s[0] & mask);
+    }
+  else if (precision == HOST_BITS_PER_WIDE_INT)
+      result = val[0] == s[0];
+  else
+    result = eq_p_large (s, cl);
+
+  return result;
+}
+
+/* Return true if THIS is not equal to OP1. */ 
+
+template <typename T>
+bool
+wide_int::operator != (T c) const
+{
+  return !(*this == c);
+}  
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+template <typename T>
+bool
+wide_int::lt_p (T c, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (c);
+  else
+    return ltu_p (c);
+}  
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+template <typename T>
+bool
+wide_int::lts_p (T c) const
+{
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    /* The values are already logically sign extended.  */
+    result = val[0] < s[0];
+  else
+    result = lts_p_large (val, len, s, cl, precision);
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+template <typename T>
+bool
+wide_int::ltu_p (T c) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (s[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = s[0];
+	}
+
+      result = x0 < x1;
+    }
+  else
+    result = ltu_p_large (val, len, s, cl);
+  return result;
+}
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+template <typename T>
+bool
+wide_int::gt_p (T c, SignOp op) const
+{
+  if (op == SIGNED)
+    return gts_p (c);
+  else
+    return gtu_p (c);
+}  
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+template <typename T>
+bool
+wide_int::gts_p (T c) const
+{
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] > s[0];
+    }
+  else
+    /* Reverse the parms and use ltu.  */
+    result = lts_p_large (s, cl, val, len, precision);
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+template <typename T>
+bool
+wide_int::gtu_p (T c) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (s[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = s[0];
+	}
+
+      result = x0 > x1;
+    }
+  else 
+    /* Reverse the parms and use ltu.  */
+    result = ltu_p_large (s, cl, val, len);
+  return result;
+}
+
+
+/* Return -1 0 or 1 depending on how THIS compares with OP1.  Signness
+   is indicated by OP.  */
+
+template <typename T>
+int
+wide_int::cmp (T c, SignOp op) const
+{
+  if (op == SIGNED)
+    return cmps (c);
+  else
+    return cmpu (c);
+}  
+
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+template <typename T>
+int
+wide_int::cmps (T c) const
+{
+  int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      if (val[0] < s[0])
+	result = -1;
+      else if (val[0] > s[0])
+	result = 1;
+      else 
+	result = 0;
+    }
+  else
+    result = cmps_large (s, cl);
+  return result;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+template <typename T>
+int
+wide_int::cmpu (T c) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (s[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = s[0];
+	}
+
+      if (x0 < x1)
+	result = -1;
+      else if (x0 == x1)
+	result = 0;
+      else
+	result = 1;
+    }
+  else
+    result = cmpu_large (s, cl);
+  return result;
+}
+
+
+/* Return the signed or unsigned min of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::min (T c, SignOp sgn) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (sgn == SIGNED)
+    return lts_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+  else
+    return ltu_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the signed or unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::min (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return lts_p (op1) ? (*this) : op1;
+  else
+    return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed or unsigned max of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::max (T c, SignOp sgn) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (sgn == SIGNED)
+    return gts_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+  else
+    return gtu_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the signed or unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::max (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return gts_p (op1) ? (*this) : op1;
+  else
+    return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed min of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::smin (T c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return lts_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the signed min of THIS and OP1. */
+
+wide_int
+wide_int::smin (const wide_int &op1) const
+{
+  return lts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed max of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::smax (T c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return gts_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the signed max of THIS and OP1. */
+
+wide_int
+wide_int::smax (const wide_int &op1) const
+{
+  return gts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned min of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::umin (T c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return ltu_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::umin (const wide_int &op1) const
+{
+  return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned max of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::umax (T c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return gtu_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::umax (const wide_int &op1) const
+{
+  return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p () const
+{
+  return only_sign_bit_p (precision);
+}
+
+/* Return true if THIS fits in a HOST_WIDE_INT with no loss of
+   precision.  */
+
+bool
+wide_int::fits_shwi_p () const
+{
+  return len == 1;
+}
+
+/* Return true if THIS fits in an unsigned HOST_WIDE_INT with no loss
+   of precision.  */
+
+bool
+wide_int::fits_uhwi_p () const
+{
+  return len == 1 
+    || (len == 2 && val[1] == 0);
+}
+
+/* Return THIS extended to PREC.  The signness of the extension is
+   specified by OP.  */
+
+wide_int 
+wide_int::ext (unsigned int prec, SignOp z) const
+{
+  if (z == UNSIGNED)
+    return zext (prec);
+  else
+    return sext (prec);
+}
+
+/* Return THIS forced to the precision of TYPE.  If this is extension,
+   the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (enum machine_mode mode, SignOp sgn) const
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (prec, sgn);
+}
+
+/* Return THIS forced to the precision and sign of TYPE.  If this is
+   extension, the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (const_tree type) const
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  SignOp sgn = TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED;
+
+  return force_to_size (prec, sgn);
+}
+
+/* Return THIS zero extended to the precision of TYPE but extends
+   using SGN.  If this is extension, the sign is set by SGN. */
+
+wide_int 
+wide_int::force_to_size (const_tree type, SignOp sgn) const
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (prec, sgn);
+}
+
+/* Return THIS forced to the precision of TYPE.  If this is extension,
+   it is signed. */
+
+wide_int 
+wide_int::sforce_to_size (enum machine_mode mode) const
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (prec, SIGNED);
+}
+
+/* Return THIS zero extended to the precision of TYPE but extends
+   using SGN.  If this is extension, it is signed. */
+
+wide_int 
+wide_int::sforce_to_size (const_tree type) const
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (prec, SIGNED);
+}
+
+/* Return THIS forced to the precision of TYPE.  If this
+   is extension, it is unsigned. */
+
+wide_int 
+wide_int::zforce_to_size (enum machine_mode mode) const
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return force_to_size (prec, UNSIGNED);
+}
+
+/* Return THIS zero extended to the precision of TYPE but extends
+   using SGN.  If this is extension, it is unsigned. */
+
+wide_int 
+wide_int::zforce_to_size (const_tree type) const
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  return force_to_size (prec, UNSIGNED);
+}
+
+/*
+ * Logicals.
+ */
+
+/* Return THIS & OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator & (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] & s[0];
+    }
+  else
+    result = and_large (s, cl);
+  return result;
+}
+
+
+/* Return THIS & ~OP1.  */
+
+template <typename T>
+wide_int
+wide_int::and_not (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] & ~s[0];
+    }
+  else
+    result = and_not_large (s, cl);
+  return result;
+}
+
+
+/* Return the logical negation (bitwise complement) of THIS.  */
+
+wide_int
+wide_int::operator ~ () const
+{
+  wide_int result;
+  int l0 = len - 1;
+
+  result.len = len;
+  result.precision = precision;
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = ~val[l0];
+      l0--;
+    }
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator | (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] | s[0];
+    }
+  else
+    result = or_large (s, cl);
+  return result;
+}
+
+
+/* Return THIS | ~OP1.  */
+
+template <typename T>
+wide_int
+wide_int::or_not (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] | ~s[0];
+    }
+  else
+    result = or_not_large (s, cl);
+  return result;
+}
+
+
+/* Return THIS ^ OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator ^ (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] ^ s[0];
+    }
+  else
+    result = xor_large (s, cl);
+  return result;
+}
+
+/*
+ * Integer arithmetic
+ */
+
+/* Return THIS + OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator + (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] + s[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = add_large (s, cl);
+  return result;
+}
+
+/* Multiply THIS and OP1.  The result is the same precision as the
+   operands, so there is no reason for signed or unsigned
+   versions.  */
+
+template <typename T>
+wide_int
+wide_int::operator * (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+  bool overflow = false;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] * s[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = mul_internal (false, false, this, s, cl, UNSIGNED, &overflow, false);
+  return result;
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.
+   OVERFLOW is set true if the result overflows.  */
+
+template <typename T>
+wide_int 
+wide_int::mul (T c, SignOp sgn, bool *overflow) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return mul_internal (false, false, this, s, cl, sgn, overflow, true);
+}
+
+/* Signed multiply THIS and OP1.  The result is the same precision as
+   the operands.  OVERFLOW is set true if the result overflows.  */
+
+template <typename T>
+wide_int
+wide_int::smul (T c, bool *overflow) const
+{
+  return mul (c, SIGNED, overflow);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is the same precision
+   as the operands.  OVERFLOW is set true if the result overflows.  */
+
+template <typename T>
+wide_int
+wide_int::umul (T c, bool *overflow) const
+{
+  return mul (c, UNSIGNED, overflow);
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.  The
+   result is twice the precision as the operands.  The signess is
+   specified with SGN.  */
+
+template <typename T>
+wide_int
+wide_int::mul_full (T c, SignOp sgn) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return mul_internal (false, true, this, s, cl, sgn, 0, false);
+}
+
+/* Signed multiply THIS and OP1.  The result is twice the precision as
+   the operands.  */
+
+template <typename T>
+wide_int
+wide_int::smul_full (T c) const
+{
+  return mul_full (c, SIGNED);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is twice the precision
+   as the operands.  */
+
+template <typename T>
+wide_int
+wide_int::umul_full (T c) const
+{
+  return mul_full (c, UNSIGNED);
+}
+
+/* Multiply THIS and OP1 and return the high part of that result.  The
+   signess is specified with SGN.  The result is the same precision as
+   the operands.  The mode is the same mode as the operands.  The
+   signess is specified with y.  */
+
+template <typename T>
+wide_int
+wide_int::mul_high (T c, SignOp sgn) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  return mul_internal (true, false, this, s, cl, sgn, 0, false);
+}
+
+/* Negate THIS.  */
+
+wide_int
+wide_int::neg () const
+{
+  wide_int z = wide_int::from_shwi (0, precision);
+  return z - *this;
+}
+
+/* Negate THIS.  Set overflow if the value cannot be negated.  */
+
+wide_int
+wide_int::neg (bool *overflow) const
+{
+  wide_int z = wide_int::from_shwi (0, precision);
+  if (only_sign_bit_p ())
+    *overflow = true;
+
+  return z - *this;
+}
+
+/* Return THIS - OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator - (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] - s[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = sub_large (s, cl);
+  return result;
+}
+
+
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is truncated.
+   Overflow is set to true if the result overflows, otherwise it is
+   not set.  */
+template <typename T>
+wide_int
+wide_int::div_trunc (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+  
+  return divmod_internal (true, this, s, cl, sgn, 
+			  &remainder, false, overflow);
+}
+
+/* Signed divide with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::sdiv_trunc (T c) const
+{
+  return div_trunc (c, SIGNED);
+}
+
+/* Unsigned divide with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::udiv_trunc (T c) const
+{
+  return div_trunc (c, UNSIGNED);
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is floor
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::div_floor (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return quotient - 1;
+  return quotient;
+}
+
+/* Unsigned divide with floor truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::udiv_floor (T c) const
+{
+  bool overflow;
+
+  return div_floor (c, UNSIGNED, &overflow);
+}
+
+/* Signed divide with floor truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::sdiv_floor (T c) const
+{
+  bool overflow;
+
+  return div_floor (c, SIGNED, &overflow);
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is ceil
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::div_ceil (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return quotient;
+      else
+	return quotient + 1;
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is round
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::div_round (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+  if (!remainder.zero_p ())
+    {
+      wide_int divisor = wide_int::from_array (s, cl, precision);
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu_large (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return quotient - 1;
+	      else 
+		return quotient + 1;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu_large (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return quotient + 1;
+	}
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing both the quotient and remainder.
+   The result is the same size as the operands.  The sign is specified
+   in SGN.  The output is truncated.  */
+
+template <typename T>
+wide_int
+wide_int::divmod_trunc (T c, wide_int *remainder, SignOp sgn) const
+{
+  bool overflow = false;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return divmod_internal (true, this, s, cl, sgn, 
+			  remainder, true, &overflow);
+}
+
+/* Signed divide/mod with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::sdivmod_trunc (T c, wide_int *mod) const
+{
+  return divmod_trunc (c, mod, SIGNED);
+}
+
+/* Unsigned divide/mod with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::udivmod_trunc (T c, wide_int *mod) const
+{
+  return divmod_trunc (c, mod, UNSIGNED);
+}
+
+/* Divide DIVISOR into THIS.  The remainder is also produced in
+   REMAINDER.  The result is the same size as the operands.  The sign
+   is specified in SGN.  The output is floor truncated.  Overflow is
+   set to true if the result overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::divmod_floor (T c, wide_int *remainder, SignOp sgn) const
+{
+  wide_int quotient;
+  bool overflow = false;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      remainder, true, &overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !(*remainder).zero_p ())
+    {
+      *remainder = *remainder - wide_int::from_array (s, cl, precision);
+      return quotient - 1;
+    }
+  return quotient;
+}
+
+/* Signed divide/mod with floor truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::sdivmod_floor (T c, wide_int *mod) const
+{
+  return divmod_floor (c, mod, SIGNED);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::mod_trunc (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  divmod_internal (true, this, s, cl, sgn, 
+			  &remainder, true, overflow);
+  return remainder;
+}
+
+/* Signed mod with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::smod_trunc (T c) const
+{
+  return mod_trunc (c, SIGNED);
+}
+
+/* Unsigned mod with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::umod_trunc (T c) const
+{
+  return mod_trunc (c, UNSIGNED);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is floor truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::mod_floor (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return remainder - wide_int::from_array (s, cl, precision);
+  return remainder;
+}
+
+/* Unsigned mod with floor truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::umod_floor (T c) const
+{
+  bool overflow;
+
+  return mod_floor (c, UNSIGNED, &overflow);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is the
+   same size as the operands.  The sign is specified in SGN.  The
+   output is ceil truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::mod_ceil (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return remainder;
+      else
+	return remainder - wide_int::from_array (s, cl, precision);
+    }
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is round truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::mod_round (T c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      wide_int divisor = wide_int::from_array (s, cl, precision);
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu_large (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return remainder + divisor;
+	      else 
+		return remainder - divisor;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu_large (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return remainder - divisor;
+	}
+    }
+  return remainder;
+}
+
+
+/* If SHIFT_COUNT_TRUNCATED is defined, truncate CNT.   
+
+   At first look, the shift truncation code does not look right.
+   Shifts (and rotates) are done according to the precision of the
+   mode but the shift count is truncated according to the bitsize of
+   the mode.  This is how real hardware works (Knuth's mix machine is
+   the only known exception to this rule, but it was never real).
+
+   On an ideal machine, like Knuth's mix machine, a shift count is a
+   word long and all of the bits of that word are examined to compute
+   the shift amount.  But on real hardware, especially on machines
+   with fast (single cycle shifts) that takes too long.  On these
+   machines, the amount of time to perform a shift dictates the cycle
+   time of the machine so corners are cut to keep this fast.  A
+   comparison of an entire 64 bit word would take something like 6
+   gate delays before the shifting can even start.
+
+   So real hardware only looks at a small part of the shift amount.
+   On ibm machines, this tends to be 1 more than what is necessary to
+   encode the shift amount.  The rest of the world looks at only the
+   minimum number of bits.  This means that only 3 gate delays are
+   necessary to set up the shifter.
+
+   On the other hand, right shifts and rotates must be according to
+   the precision or the operation does not make any sense. 
+
+   This function is called in two contexts.  If OP == TRUNC, this
+   function provides a count that matches the semantics of the target
+   machine depending on the value of SHIFT_COUNT_TRUNCATED.  Note that
+   if SHIFT_COUNT_TRUNCATED is not defined, this function may produce
+   -1 as a value if the shift amount is greater than the bitsize of
+   the mode.  -1 is a surrogate for a very large amount.
+
+   If OP == NONE, then this function always truncates the shift value
+   to the bitsize because this shifting operation is a function that
+   is internal to GCC.  */
+
+inline int
+wide_int::trunc_shift (const HOST_WIDE_INT *cnt, unsigned int len ATTRIBUTE_UNUSED,
+		       unsigned int bitsize, ShiftOp trunc_op)
+{
+  if (trunc_op == TRUNC)
+    {
+      gcc_checking_assert (bitsize != 0);
+#ifdef SHIFT_COUNT_TRUNCATED
+      return cnt[0] & (bitsize - 1);
+#else
+      if (cnt[0] < bitsize && cnt[0] >= 0 && len == 1)
+	return cnt[0];
+      else 
+	return -1;
+#endif
+    }
+  else if (bitsize == 0)
+    return cnt[0];
+  else
+    return cnt[0] & (bitsize - 1);
+}
+
+/* Left shift THIS by C.  See the definition of Op.TRUNC for how to
+   set TRUNC_OP.  Since this is used internally, it has the ability to
+   specify the BITSIZE  and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+template <typename T>
+wide_int
+wide_int::lshift (T c, unsigned int bitsize, 
+		  unsigned int res_prec, ShiftOp trunc_op) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+  HOST_WIDE_INT shift;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  if (res_prec == 0)
+    res_prec = precision;
+
+  shift = trunc_shift (s, cl, bitsize, trunc_op);
+  if (shift == -1)
+    result = wide_int::zero (precision);
+  else if (shift == 0 && res_prec == precision)
+    result = *this;
+  /* Handle the simple case quickly.   */
+  else if (res_prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.precision = res_prec;
+      result.len = 1;
+      result.val[0] = val[0] << shift;
+    }
+  else
+    result = lshift_large (shift, res_prec);
+  return result;
+}
+
+/* Rotate THIS left by Y within its precision.  */
+
+template <typename T>
+wide_int
+wide_int::lrotate (T c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return lrotate ((unsigned HOST_WIDE_INT)s[0]);
+}
+
+
+/* Rotate THIS left by CNT within its precision.  */
+
+wide_int
+wide_int::lrotate (unsigned HOST_WIDE_INT cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (cnt);
+  right = rshiftu (precision - cnt);
+  result = left | right;
+
+  return result;
+}
+
+
+/* Right shift THIS by Y.  SGN indicates the sign.  TRUNC_OP indicates the
+   truncation option.  */
+
+template <typename T>
+wide_int
+wide_int::rshift (T c, SignOp sgn, 
+		  unsigned int bitsize, ShiftOp trunc_op) const
+{
+  if (sgn == UNSIGNED)
+    return rshiftu (c, bitsize, trunc_op);
+  else
+    return rshifts (c, bitsize, trunc_op);
+}
+
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set TRUNC_OP.  */
+
+template <typename T>
+wide_int
+wide_int::rshiftu (T c, unsigned int bitsize,
+		   ShiftOp trunc_op) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+  HOST_WIDE_INT shift;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  shift = trunc_shift (s, cl, bitsize, trunc_op);
+  
+  if (shift == 0)
+    result = copy ();
+  else if (shift == -1)
+    result = wide_int::zero (precision);
+  else if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* Handle the simple case quickly.   */
+      unsigned HOST_WIDE_INT x = val[0];
+
+      result.precision = precision;
+      result.len = 1;
+
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	x = zext_hwi (x, precision);
+
+      result.val[0] = x >> shift;
+    }
+  else 
+    result = rshiftu_large (shift);
+  return result;
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set TRUNC_OP.  */
+
+template <typename T>
+wide_int
+wide_int::rshifts (T c, unsigned int bitsize,
+		   ShiftOp trunc_op) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+  HOST_WIDE_INT shift;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  shift = trunc_shift (s, cl, bitsize, trunc_op);
+  
+  if (shift == 0)
+    result = copy ();
+  else if (shift == -1)
+    result = wide_int::zero (precision);
+  else if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* Handle the simple case quickly.   */
+      HOST_WIDE_INT x = val[0];
+
+      result.precision = precision;
+      result.len = 1;
+      result.val[0] = x >> shift;
+    }
+  else 
+    result = rshifts_large (shift);
+  return result;
+}
+
+/* Rotate THIS right by Y within its precision.  */
+
+
+template <typename T>
+wide_int
+wide_int::rrotate (T c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+
+  return rrotate ((unsigned HOST_WIDE_INT) s[0]);
+}
+
+
+/* Rotate THIS left by CNT within its precision.  */
+
+wide_int
+wide_int::rrotate (unsigned HOST_WIDE_INT cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (precision - cnt);
+  right = rshiftu (cnt);
+  result = left | right;
+
+  return result;
+}
+
+/* tree related routines.  */
+
+extern tree wide_int_to_tree (tree type, const wide_int &cst);
+extern tree wide_int_to_infinite_tree (tree type, const wide_int &cst, 
+				       unsigned int prec);
+extern tree force_fit_type_wide (tree, const wide_int &, int, bool);
+
+/* real related routines.  */
+extern wide_int real_to_integer (const REAL_VALUE_TYPE *, bool *, int);
+extern wide_int decimal_real_to_integer (const REAL_VALUE_TYPE *, bool *, int);
+
+
+/* Conversion to and from GMP integer representations.  */
+
+void mpz_set_wide_int (mpz_t, wide_int, bool);
+wide_int mpz_get_wide_int (const_tree, mpz_t, bool);
+#endif /* GENERATOR FILE */
+
+#endif /* WIDE_INT_H */

[-- Attachment #3: p4-6.clog --]
[-- Type: text/plain, Size: 243 bytes --]

2013-04-16  Kenneth Zadeck <zadeck@naturalbridge.com>

	* Makefile.in (wide-int.c, wide-int.h): New files.
	* wide-int.c: New file containing implementation of wide_int class.
	* wide-int.h: New file containing public spec for wide_int class.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-17  0:49                                                                                 ` Kenneth Zadeck
                                                                                                     ` (2 preceding siblings ...)
  2013-04-17 15:01                                                                                   ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Kenneth Zadeck
@ 2013-04-19 15:35                                                                                   ` Richard Biener
  2013-04-22  7:15                                                                                     ` Kenneth Zadeck
                                                                                                       ` (2 more replies)
  3 siblings, 3 replies; 217+ messages in thread
From: Richard Biener @ 2013-04-19 15:35 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On Tue, Apr 16, 2013 at 10:07 PM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
> Richard,
>
> I made major changes to wide-int along the lines you suggested. Each of the
> binary operations is now a template.
> There are 5 possible implementations of those operations, one for each of
> HWI, unsigned HWI, wide-int, rtl, and tree.   Note that this is not exactly
> as you suggested, but it is along the same lines.
>
> The HWI template sign extends the value to the precision of the first
> operand, the unsigned HWI is the same except that it is an unsigned
> extension.   The wide-int version is used as before, but is in truth rarely
> used.  The rtl and tree "logically" convert the value to a wide-int but in
> practice do something more efficient than converting to the wide-int.   What
> they do is look inside the rtl or the tree and pass a pointer to the data
> and a length to the binary operation.  This is perfectly safe in the
> position of a second operand to the binary operation because the lifetime is
> guaranteed to be very short.  The wide-int implementation was also modified
> to do the same pointer trick allowing all 5 templates to share the same use
> of the data.
>
> Note that currently the tree code is more crufty than one would like.   This
> will clean up nicely when the tree-cst is changed to represent the value
> with an array and a length field.
>
> So now, at least for the second operand of binary operations, the storage is
> never copied.    I do not believe that there is a good similar trick for the
> first operand.  i did not consider something like wide_int::add (a, b) to be
> a viable option; it seems to mis the point of using an object oriented
> language.   So I think that you really have to copy the data into an
> instance of a wide int.
>
> However, while all of this avoids ever having to pass a precision into the
> second operand, this patch does preserve the finite math implementation of
> wide-int.    Finite math is really what people expect an optimizer to do,
> because it seamlessly matches what the machine is going to do.
>
> I hope at this point, i can get a comprehensive review on these patches.   I
> believe that I have done what is required.
>
> There are two other patches that will be submitted in the next few minutes.
> The first one is an updated version of the rtl level patch.   The only
> changes from what you have seen before are that the binary operations now
> use the templated binary operations.  The second one is the first of the
> tree level patches.   It converts builtins.c to use both use wide-int and it
> removes all assumptions that tree-csts are built with two HWIs.
>
> Once builtins.c is accepted, i will convert the rest of the middle end
> patches.   They will all be converted in a similar way.

+   number of elements of the vector that are in use.  When LEN *
+   HOST_BITS_PER_WIDE_INT < the precision, the value has been
+   compressed.  The values of the elements of the vector greater than
+   LEN - 1. are all equal to the highest order bit of LEN.

equal to the highest order bit of element LEN - 1. ?

Especially _not_ equal to the precision - 1 bit of the value, correct?

+   The representation does not contain any information inherant about
+   signedness of the represented value, so it can be used to represent
+   both signed and unsigned numbers.   For operations where the results
+   depend on signedness (division, comparisons), the signedness must
+   be specified separately.  For operations where the signness
+   matters, one of the operands to the operation specifies either
+   wide_int::SIGNED or wide_int::UNSIGNED.

The last sentence is somehow duplicated.

+   The numbers are stored as sign entended numbers as a means of
+   compression.  Leading HOST_WIDE_INTS that contain strings of either
+   -1 or 0 are removed as long as they can be reconstructed from the
+   top bit that is being represented.

I'd put this paragraph before the one that talks about signedness, next
to the one that already talks about encoding.

+   All constructors for wide_int take either a precision, an enum
+   machine_mode or tree_type.  */

That's probably no longer true (I'll now check).

+class wide_int {
+  /* Internal representation.  */
+
+  /* VAL is set to a size that is capable of computing a full
+     multiplication on the largest mode that is represented on the
+     target.  The full multiplication is use by tree-vrp.  tree-vpn
+     currently does a 2x largest mode by 2x largest mode yielding a 4x
+     largest mode result.  If operations are added that require larger
+     buffers, then VAL needs to be changed.  */
+  HOST_WIDE_INT val[WIDE_INT_MAX_ELTS];
+  unsigned short len;
+  unsigned int precision;

I wonder if there is a technical reason to stick to HOST_WIDE_INTs?
I'd say for efficiency HOST_WIDEST_FAST_INT would be more appropriate
(to get a 32bit value on 32bit x86 for example).  I of course see that
conversion to/from HOST_WIDE_INT is an important operation
that would get slightly more complicated.

Maybe just quickly checking the code generated on 32bit x86 for
HOST_WIDE_INT vs. HOST_WIDEST_FAST_INT tells us whether
it's worth considering (it would be bad if each add/multiply would
end up calling to libgcc for example - I know that doesn't happen
for x86, but maybe it would happen for an arm hosted gcc
targeting x86_64?)

+  enum ShiftOp {
+    NONE,
+    /* There are two uses for the wide-int shifting functions.  The
+       first use is as an emulation of the target hardware.  The
+       second use is as service routines for other optimizations.  The
+       first case needs to be identified by passing TRUNC as the value
+       of ShiftOp so that shift amount is properly handled according to the
+       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
+       amount is always truncated by the bytesize of the mode of
+       THIS.  */
+    TRUNC
+  };

double-int simply honors SHIFT_COUNT_TRUNCATED.  Why differ
from that (and thus change behavior in existing code - not sure if you
do that with introducing wide-int)?

+  enum SignOp {
+    /* Many of the math functions produce different results depending
+       on if they are SIGNED or UNSIGNED.  In general, there are two
+       different functions, whose names are prefixed with an 'S" and
+       or an 'U'.  However, for some math functions there is also a
+       routine that does not have the prefix and takes an SignOp
+       parameter of SIGNED or UNSIGNED.  */
+    SIGNED,
+    UNSIGNED
+  };

You seem to insist on that.  It should propagate to the various parts
of the compiler that have settled for the 'uns' integer argument.
Having one piece behave different is just weird.  I suppose I will
find code like

    wi.ext (prec, uns ? UNSIGNED : SIGNED)

in your conversion?

+  static wide_int from_shwi (HOST_WIDE_INT op0,
+                            unsigned int precision, bool *overflow = 0);

+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT t = sext_hwi (op0, precision);
+      if (t != op0 && overflow)
+       *overflow = true;
+      op0 = t;
+    }

Hm.  I'd say input values should be properly extended already (we certainly
expect that from RTL or tree constants).  So we might want to assert the
above instead of tracking it via *overflow.

+  static wide_int from_array (const HOST_WIDE_INT* op0,
+                             unsigned int len,
+                             unsigned int precision, bool need_canon = true);
+  inline static wide_int from_array (const HOST_WIDE_INT* op0,
+                                    unsigned int len,
+                                    enum machine_mode mode);
+  inline static wide_int from_array (const HOST_WIDE_INT* op0,
+                                    unsigned int len,
+                                    const_tree type);

I still don't like the overloads precision vs. machine_mode vs. tree type.
It's much more explanative what you specify here if you write

  from_array (&x, len, GET_MODE_PRECISION (mode))

instead of

  from_array (&x, len, mode)

and it's not that much more typing either.

+  static wide_int from_double_int (double_int,
+                                  unsigned int precision);
+  inline static wide_int from_double_int (double_int, enum machine_mode);

this one would lack the tree type overload (I of course think it has an
excessive overload for machine_mode).

+  inline HOST_WIDE_INT to_shwi (unsigned int prec = 0) const;
+  inline unsigned HOST_WIDE_INT to_uhwi (unsigned int prec = 0) const;

this is

   wi.sext (prec);
   wi.to_shwi ();

which is less odd than handling prec == 0 specially.

+  static wide_int max_value (unsigned int prec,
+                            unsigned int precision, SignOp sgn);

two precisions - ugh ;)  In some places having to have a precision is ugly :/

+  inline static wide_int minus_one (unsigned int prec);
+  inline static wide_int zero (unsigned int prec);
+  inline static wide_int one (unsigned int prec);
+  inline static wide_int two (unsigned int prec);

here as well.  I see two (1) properly truncates the value to zero ;)
It just comes to my mind that these could have "arbitrary" precision.
"arbitrary" == MAX_SIZE * HOST_BITS_PER_WIDE_INT.  Which
would get us back to mixed precision operations ...


+  /* Printing functions.  */
+
+  void print_dec (char *buf, SignOp sgn) const;
+  void print_dec (FILE *file, SignOp sgn) const;
+  void print_decs (char *buf) const;
+  void print_decs (FILE *file) const;
+  void print_decu (char *buf) const;
+  void print_decu (FILE *file) const;
+  void print_hex (char *buf) const;
+  void print_hex (FILE *file) const;

making those non-member functions would allow getting rid of stdio.h
from wide-int.h (similar making the tree / rtx / mode argument methods
either standalone or making them templates and externalizing the
implementation to a separate template class would get rid of the
rtl / tree dependency)

+  inline bool neg_p () const;

how can you test that?  wide-int doesn't have sign information.

+bool
+wide_int::neg_p () const
+{
+  return sign_mask () != 0;

not exactly efficient either ...

+HOST_WIDE_INT
+wide_int::sign_mask () const
+{
+  int i = len - 1;
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
+           >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* VRP appears to be badly broken and this is a very ugly fix.  */
+  if (i >= 0)
+    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
+
+  gcc_unreachable ();
+#if 0
+  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
+#endif
+}

I can't see what's the "fix".  It seems to be equivalent to the commented out
code.  Apart from not handling len == 0 for which you ICE then.

Back to neg_p ... it computes wrong information.
from_uwhi (-1, HOST_BITS_PER_WIDE_INT).neg_p () returns true.

I suppose you want to rename it to msb () (implementing that efficiently
and using it from sign_mask, too)

+  template <typename T>
+    inline bool gt_p (T c, SignOp sgn) const;
+  template <typename T>
+    inline bool gts_p (T c) const;
+  template <typename T>
+    inline bool gtu_p (T c) const;

it's bad that we can't use the sign information we have available in almost
all cases ... (where precision is not an exact multiple of
HOST_BITS_PER_WIDE_INT
and len == precision / HOST_BITS_PER_WIDE_INT).  It isn't hard to encode
a sign - you just have to possibly waste a word of zeroes for positive
values where at the moment precision is an exact multiple of
HOST_BIST_PER_WIDE_INT and len == precision / HOST_BITS_PER_WIDE_INT.
Which of course means that the encoding can be one word larger than
maximally required by 'precision'.

+  wide_int force_to_size (unsigned int precision, SignOp sgn) const;
+  inline wide_int force_to_size (enum machine_mode mode, SignOp sgn) const;
+  inline wide_int force_to_size (const_tree type) const;
+  inline wide_int force_to_size (const_tree type, SignOp sgn) const;
+
+  inline wide_int sforce_to_size (enum machine_mode mode) const;
+  inline wide_int sforce_to_size (const_tree type) const;
+  inline wide_int zforce_to_size (enum machine_mode mode) const;
+  inline wide_int zforce_to_size (const_tree type) const;

too many overloads again

Looking at

+template <typename T>
+wide_int
+wide_int::operator & (T c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  int cl;
+
+  s = to_shwi2 (ws, &cl, c);
+

I see

+  template <typename T>
+  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int *l, T x)
+  {
+    s[0] = x;
+    if (~(T)0 < (T)0
...

+  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s
ATTRIBUTE_UNUSED,
+                                       int *l, const wide_int &y)
+  {
+    *l = y.len;
...

I think you want to use template specialization here, not overloading.  Thus,

  template <>
  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int
*l, const wide_int &y)

and adjust the HWI case to look like

  template <typename T>
  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int
*l, const T& x)

you want to move that ~(T)0 < (T)0 check up to template substitution level
to allow SFINAE to disable the template if that's not computable.

+    s[0] = x;
+    if (~(T)0 < (T)0
+       || sizeof (T) < sizeof (HOST_WIDE_INT))
+      {
+       *l = 1;
+      }
+    else
+      {
+       s[1] = 0;
+       *l = 2;

that's only required if the MSB is set, otherwise it's not properly compressed

+      }
+    return s;

hmm, looking at from_uhwi I see that you are adding the extra zero words
as I suggested ... which means you _do_ have reliable sign information
available (well, not for the case where len would end up bigger than MAX_LEN).
So - can we simplify some things with that?  I can think of the ordered
comparisons for example.  Also the encoding description should be
clarified that there _is_ sign information available (and that len can be
bigger than precision / HOST_BITS_PER_WIDE_INT).

Returning to to_shwi2 (odd name, btw):

+       /* Copy the result because it does not fit in two HWIs.  */
+       s[0] = TREE_INT_CST_LOW (tcst);
+       s[1] = TREE_INT_CST_HIGH (tcst);
+       s[2] = 0;
+       *l = 3;
+       return s;

ah, this is why you need the extra argument ;)  Btw, what happens
when a proper encoding does not fit in MAX_LEN words?  That is,
we'd need an extra zero word?

+  /* There should logically be an overload for rtl here, but it cannot
+     be here because of circular include issues.  It is in rtl.h.  */
+  static inline const HOST_WIDE_INT* to_shwi2
+    (HOST_WIDE_INT *s ATTRIBUTE_UNUSED, int *l, rtx rcst);

in rtl.c I suppose.  Btw, this is why I'm suggesting to defer implementation
to a template - you can implement that outside of wide-int.h even without
declaring the specialization here.

Is there an accessible branch with the wide-int work?  I may be tempted
to propose some changes in form of patches.  If not then I think the
work is in a state that is suitable to put on a merge-branch.

+wide_int
+wide_int::add (const wide_int &op1, SignOp sgn, bool *overflow) const
+{
...
+  /* Uncompress the rest.  */
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = val[i];
+      o1 = mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }
+  for (i = len; i < op1.len; i++)
+    {
+      o0 = mask0;
+      o1 = op1.val[i];
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      old_carry = carry;
+      carry = x < o0;
+    }

Cut & paste error here I think.  at least one should run up to this->len, no?
And the first loop should run to min (len, op1.len) only.  How much
testing coverage does the code have for "interesting" values?
A standalone testing program will probably reveal such issues (due to
the rich-ness of the current API covering everything will be hard :/)

Looking at

+HOST_WIDE_INT
+wide_int::sign_mask () const
+{
+  int i = len - 1;
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
+           >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* VRP appears to be badly broken and this is a very ugly fix.  */
+  if (i >= 0)
+    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
+
+  gcc_unreachable ();
+#if 0
+  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
+#endif
+}

again - this looks like it does overly complicated work.  Our encoding
of values guarantees that the following is correct:

HOST_WIDE_INT
wide_int::sign_mask () const
{
  if (val[len - 1] < 0)
    return -1;
  else
    return 0;
}

I suppose quite some code can be simplified that calls sign_mask
currently (thanks to the changed encoding).

back to ::add ():

+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec == 0)
+    {
+      if (sgn == wide_int::SIGNED)
+       {
+         if (((!(o0 ^ o1)) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
+           *overflow = true;

shouldn't this share code with the non-overflow add_large and simply
do overflow detection conditional on overlflow being non-NULL?
Because the add_large code seems to be correct with respect to
the issues noted above ...

+ ex:
+  result.canonize ();
+  return result;
+}

canonizing is not strictly necessary - in fact it is unlikely to do
something useful most of the time.  I'd say we should only
canonize before building a tree or RTL with that representation.
Note that canonize is wrong, too:

+wide_int::canonize ()
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT top;
+  int i;
+
+  if (len > blocks_needed)
+    len = blocks_needed;

that will set a UHWI -1 to have len == 1, ignoring the extra needed
zero word.  Thus, either BLOCKS_NEEDED is broken or its
uses need to be audited.

+
+  /* Clean up the top bits for any mode that is not a multiple of a HWI.  */
+  if (len == blocks_needed && small_prec)
+    val[len - 1] = sext_hwi (val[len - 1], small_prec);

That's not necessary.  By construction all arithmetic operations will
preserve proper extension.  And you unconditionally sign-extend
small precision "large" positive constants here which is even wrong
(-1U, precision == 32, HWI == 64, original rep { 0x00..00fffff }, broken
{ 0xfff...fff } ).

+  if (len == 1)
+    return;

in fact for len == 1 we should do nothing in this function from the start.
Callers that also want to properly sign or zero extend the result value
should do so using ext (), not abuse another implementation inside
canonize () (which should only optimize the encoding).

Ok, I'll stop reviewing here.  It's a lot better than before - thanks for
doing the changes.

I still like you to cut down the interface somewhat and _test_ what
is remaining.  Put the code on a branch off trunk so I and others can
produce patches against it.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-19 15:35                                                                                   ` Richard Biener
@ 2013-04-22  7:15                                                                                     ` Kenneth Zadeck
  2013-04-22 15:21                                                                                       ` Richard Biener
  2013-04-22 18:53                                                                                     ` Kenneth Zadeck
  2013-05-02 17:21                                                                                     ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Kenneth Zadeck
  2 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-22  7:15 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

Richard,

i pulled these two frags out of your comments because i wanted to get 
some input from you on it while i addressed the other issues you raised.

> +  enum SignOp {
> +    /* Many of the math functions produce different results depending
> +       on if they are SIGNED or UNSIGNED.  In general, there are two
> +       different functions, whose names are prefixed with an 'S" and
> +       or an 'U'.  However, for some math functions there is also a
> +       routine that does not have the prefix and takes an SignOp
> +       parameter of SIGNED or UNSIGNED.  */
> +    SIGNED,
> +    UNSIGNED
> +  };
>
> You seem to insist on that.  It should propagate to the various parts
> of the compiler that have settled for the 'uns' integer argument.
> Having one piece behave different is just weird.  I suppose I will
> find code like
>
>      wi.ext (prec, uns ? UNSIGNED : SIGNED)

there is a lot more flexibility on my part than you perceive with 
respect to this point.   My primary issue is that i do not want to have 
is an interface that has 0 and 1 as a programmer visible part.   Beyond 
that i am open to suggestion.

The poster child of my hate are the host_integer_p and the tree_low_cst 
interfaces. I did not want the wide int stuff to look like these.  I see 
several problems with these:

1) of the 314 places where tree_low_cst is called in the gcc directory 
(not the subdirectories where the front ends live), NONE of the calls 
have a variable second parameter.   There are a handful of places, as 
one expects, in the front ends that do, but NONE in the middle end.
2) there are a small number of the places where host_integer_p is called 
with one parameter and then it is followed by a call to tree_low_cst 
that has the value with the other sex.   I am sure these are mistakes, 
but having the 0s and 1s flying around does not make it easy to spot them.
3) tree_low_cst implies that the tree cst has only two hwis in it.

While i do not want to propagate an interface with 0 and 1 into 
wide-int, i can understand your dislike of having a wide-int only 
solution for this.

I will point out that for your particular example, uns is almost always 
set by a call to TYPE_UNSIGNED.  There could easily be a different type 
accessor that converts this part of the type to the right thing to pass 
in here.   I think that there is certainly some place for there to be a 
unified SYMBOLIC api that controls the signedness everywhere in the 
compiler.

I would like to move toward this direction, but you have been so 
negative to the places where i have made it convenient to directly 
convert from tree or rtl into or out of wide-int that i have hesitated 
to do something that directly links trees and wide-int. So i would like 
to ask you what would like?



> +  template <typename T>
> +    inline bool gt_p (T c, SignOp sgn) const;
> +  template <typename T>
> +    inline bool gts_p (T c) const;
> +  template <typename T>
> +    inline bool gtu_p (T c) const;
>
> it's bad that we can't use the sign information we have available in almost
> all cases ... (where precision is not an exact multiple of
> HOST_BITS_PER_WIDE_INT
> and len == precision / HOST_BITS_PER_WIDE_INT).  It isn't hard to encode
> a sign - you just have to possibly waste a word of zeroes for positive
> values where at the moment precision is an exact multiple of
> HOST_BIST_PER_WIDE_INT and len == precision / HOST_BITS_PER_WIDE_INT.
> Which of course means that the encoding can be one word larger than
> maximally required by 'precision'.
>
Going back to point 1 above,   the front ends structure the middle end 
code where (generally) the sign that is used is encoded in the operator 
that one is looking at.    So the majority of uses in the middle end 
this fall into the second or third templates and the first template is 
there as a convenience routine for the middle ends.
The front ends certainly use the first template.

This is how the rtl level has survived so long without a sign bit in the 
modes, the operators tell the whole story.   The truth is that in the 
middle end, the story is the same - it is the operators (most of the 
time) that drive the calls being made.

There is an assumption that you are making that i certainly do not 
believe is true in the backends and i kind of doubt is true in the 
middle ends.   That is that the sign of the compare ALWAYS matches the 
sign of the operands.   Given that i have never seen any code that 
verifies this in the middle end, i am going to assume that it is not 
true, because it is always true in gcc that anything that we do not 
explicitly verify generally turns out to only be generally true and you 
can spend your life tracking down the end cases.  This is a needless 
complication.
At the rtl level, this is completely doomed by the GEN_INT which neither 
takes a mode or an indication of sign.   To assume that there is any 
meaningful sign information there is a horror story waiting to be 
written ("sure what could go wrong if we go into the old house?  whats 
that i hear, it sounds like a chain saw ....").

The api that i have is independent of the rep that i happen to use 
inside of wide-ints.   The fact that it might be work is really just an 
accident.   Gimple was designed (and rtl just happened) so that the 
operators carry the information that is needed.   The fact that those 
operators are generally redundant with the types is a byproduct of the 
strong typing of the middle ends.   With this respect, i think i have 
the right interface.

Kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-22  7:15                                                                                     ` Kenneth Zadeck
@ 2013-04-22 15:21                                                                                       ` Richard Biener
  2013-04-23  8:11                                                                                         ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-22 15:21 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On Sun, Apr 21, 2013 at 10:54 PM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
> Richard,
>
> i pulled these two frags out of your comments because i wanted to get some
> input from you on it while i addressed the other issues you raised.
>
>
>> +  enum SignOp {
>> +    /* Many of the math functions produce different results depending
>> +       on if they are SIGNED or UNSIGNED.  In general, there are two
>> +       different functions, whose names are prefixed with an 'S" and
>> +       or an 'U'.  However, for some math functions there is also a
>> +       routine that does not have the prefix and takes an SignOp
>> +       parameter of SIGNED or UNSIGNED.  */
>> +    SIGNED,
>> +    UNSIGNED
>> +  };
>>
>> You seem to insist on that.  It should propagate to the various parts
>> of the compiler that have settled for the 'uns' integer argument.
>> Having one piece behave different is just weird.  I suppose I will
>> find code like
>>
>>      wi.ext (prec, uns ? UNSIGNED : SIGNED)
>
>
> there is a lot more flexibility on my part than you perceive with respect to
> this point.   My primary issue is that i do not want to have is an interface
> that has 0 and 1 as a programmer visible part.   Beyond that i am open to
> suggestion.
>
> The poster child of my hate are the host_integer_p and the tree_low_cst
> interfaces. I did not want the wide int stuff to look like these.  I see
> several problems with these:
>
> 1) of the 314 places where tree_low_cst is called in the gcc directory (not
> the subdirectories where the front ends live), NONE of the calls have a
> variable second parameter.   There are a handful of places, as one expects,
> in the front ends that do, but NONE in the middle end.
> 2) there are a small number of the places where host_integer_p is called
> with one parameter and then it is followed by a call to tree_low_cst that
> has the value with the other sex.   I am sure these are mistakes, but having
> the 0s and 1s flying around does not make it easy to spot them.
> 3) tree_low_cst implies that the tree cst has only two hwis in it.
>
> While i do not want to propagate an interface with 0 and 1 into wide-int, i
> can understand your dislike of having a wide-int only solution for this.
>
> I will point out that for your particular example, uns is almost always set
> by a call to TYPE_UNSIGNED.  There could easily be a different type accessor
> that converts this part of the type to the right thing to pass in here.   I
> think that there is certainly some place for there to be a unified SYMBOLIC
> api that controls the signedness everywhere in the compiler.
>
> I would like to move toward this direction, but you have been so negative to
> the places where i have made it convenient to directly convert from tree or
> rtl into or out of wide-int that i have hesitated to do something that
> directly links trees and wide-int. So i would like to ask you what would
> like?

Ideally I'd like the wide-int introduction to _not_ be the introduction of
a unified symbolic way that controls signedness.  We do have two
kinds of interfaces currently - one that uses different API entries,
like build_int_cstu vs. build_int_cst or double_int::from_shwi vs. from_uhwi,
and one that uses the aforementioned integer flag 'uns' with 0 being
signed and 1 being unsigned.

I think the _uhwi vs. _shwi and _cstu variants are perfectly fine
(but only for compile-time constant uses as you say), and the wide-int
interface makes use of this kind, too.

Proposing a better API for the 'uns' flag separately from wide-int would
be a better way to get anybody else than me chime in (I have the feeling
that the wide-int series seems to scare off every other reviewer besides me...).
I can live with the SIGNED/UNSIGNED enum, but existing APIs should
be changed to use that.

For wide-int I suggest to go the route you don't want to go.  Stick to
existing practice and use the integer 'uns' flag.  It's as good as
SIGNED/UNSIGNED for _variable_ cases (and yes, a lot less descriptive
for constant cases).  For wide-int, always add a static interface
if there is a variable one and convert variable uses to the proper static
interface.

That said, a lot of my pushback is because I feel a little lonesome in this
wide-int review and don't want to lone-some decide about that (generic)
interface part as well.

>> +  template <typename T>
>> +    inline bool gt_p (T c, SignOp sgn) const;
>> +  template <typename T>
>> +    inline bool gts_p (T c) const;
>> +  template <typename T>
>> +    inline bool gtu_p (T c) const;
>>
>> it's bad that we can't use the sign information we have available in
>> almost
>> all cases ... (where precision is not an exact multiple of
>> HOST_BITS_PER_WIDE_INT
>> and len == precision / HOST_BITS_PER_WIDE_INT).  It isn't hard to encode
>> a sign - you just have to possibly waste a word of zeroes for positive
>> values where at the moment precision is an exact multiple of
>> HOST_BIST_PER_WIDE_INT and len == precision / HOST_BITS_PER_WIDE_INT.
>> Which of course means that the encoding can be one word larger than
>> maximally required by 'precision'.
>>
> Going back to point 1 above,   the front ends structure the middle end code
> where (generally) the sign that is used is encoded in the operator that one
> is looking at.    So the majority of uses in the middle end this fall into
> the second or third templates and the first template is there as a
> convenience routine for the middle ends.
> The front ends certainly use the first template.
>
> This is how the rtl level has survived so long without a sign bit in the
> modes, the operators tell the whole story.   The truth is that in the middle
> end, the story is the same - it is the operators (most of the time) that
> drive the calls being made.

With the difference RTL vs. tree that tree knows about undefined overflow
for signed plus while RTL does not (there isn't a signed plus).  And that
tree gets the operator signedness from the sign of the operands.

> There is an assumption that you are making that i certainly do not believe
> is true in the backends and i kind of doubt is true in the middle ends.
> That is that the sign of the compare ALWAYS matches the sign of the
> operands.   Given that i have never seen any code that verifies this in the
> middle end, i am going to assume that it is not true, because it is always
> true in gcc that anything that we do not explicitly verify generally turns
> out to only be generally true and you can spend your life tracking down the
> end cases.  This is a needless complication.
> At the rtl level, this is completely doomed by the GEN_INT which neither
> takes a mode or an indication of sign.   To assume that there is any
> meaningful sign information there is a horror story waiting to be written
> ("sure what could go wrong if we go into the old house?  whats that i hear,
> it sounds like a chain saw ....").

Well .. ;)  If you constructed a wide-int constant A from the signed number
-10465 and a wide-int constant B from the unsigned number 921, then
if you ask whether A is less than B then I expect the answer 'yes'.  If
you ask whether A is unsigned less than B (ltu_p) then I'd be confused
and be tempted to error out.  You should have first converted A to unsigned,
that is, zero-extend it from its precision (which in my wide-int speak
simply results in another signed but positive number).  That is,
having ltu_p interpreting a value as different value sounds wrong.

> The api that i have is independent of the rep that i happen to use inside of
> wide-ints.   The fact that it might be work is really just an accident.
> Gimple was designed (and rtl just happened) so that the operators carry the
> information that is needed.   The fact that those operators are generally
> redundant with the types is a byproduct of the strong typing of the middle
> ends.   With this respect, i think i have the right interface.

The api may be independent of the rep - but it doesn't make actual API
use independent of the information present in the rep.  If the API allows
for "mismatches", like feeding a negative value to a ltu_p call, then
I view it as inherently fragile and unclean.

That said, all numbers are part of the infinite precision signed set of numbers
and we can compare them.  And the current wide-int representation seems
to be powerful enough to place each wide-int into that number space
unambiguously.  So why not use that property to clean up the API and
make it less error-prone to use?

Richard.

> Kenny
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-19 15:35                                                                                   ` Richard Biener
  2013-04-22  7:15                                                                                     ` Kenneth Zadeck
@ 2013-04-22 18:53                                                                                     ` Kenneth Zadeck
  2013-04-22 19:17                                                                                       ` richard, i accidently pushed send rather than save, the previous email was not finished, just ignore it Kenneth Zadeck
  2013-05-02 17:21                                                                                     ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Kenneth Zadeck
  2 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-22 18:53 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On 04/19/2013 09:31 AM, Richard Biener wrote:
> +   number of elements of the vector that are in use.  When LEN *
> +   HOST_BITS_PER_WIDE_INT < the precision, the value has been
> +   compressed.  The values of the elements of the vector greater than
> +   LEN - 1. are all equal to the highest order bit of LEN.
>
> equal to the highest order bit of element LEN - 1. ?
Fixed, you are correct.

I have gone thru the entire wide-int patch to clean this up.   The 
bottom line is that if the precision is not a multiple of the size of a 
HWI then everything above that precision is assumed to be identical to 
the sign bit.

> Especially _not_ equal to the precision - 1 bit of the value, correct?
I do not understand your question here, because in the case talked about 
above, the bit at precision - 1 would not have been explicitly represented.

Anyway,  i went thru this top part carefully and made many things clearer.
> +   The representation does not contain any information inherant about
> +   signedness of the represented value, so it can be used to represent
> +   both signed and unsigned numbers.   For operations where the results
> +   depend on signedness (division, comparisons), the signedness must
> +   be specified separately.  For operations where the signness
> +   matters, one of the operands to the operation specifies either
> +   wide_int::SIGNED or wide_int::UNSIGNED.
>
> The last sentence is somehow duplicated.
fixed
>
> +   The numbers are stored as sign entended numbers as a means of
> +   compression.  Leading HOST_WIDE_INTS that contain strings of either
> +   -1 or 0 are removed as long as they can be reconstructed from the
> +   top bit that is being represented.
>
> I'd put this paragraph before the one that talks about signedness, next
> to the one that already talks about encoding.
done
> +   All constructors for wide_int take either a precision, an enum
> +   machine_mode or tree_type.  */
>
> That's probably no longer true (I'll now check).
yes you are correct

> +class wide_int {
> +  /* Internal representation.  */
> +
> +  /* VAL is set to a size that is capable of computing a full
> +     multiplication on the largest mode that is represented on the
> +     target.  The full multiplication is use by tree-vrp.  tree-vpn
> +     currently does a 2x largest mode by 2x largest mode yielding a 4x
> +     largest mode result.  If operations are added that require larger
> +     buffers, then VAL needs to be changed.  */
> +  HOST_WIDE_INT val[WIDE_INT_MAX_ELTS];
> +  unsigned short len;
> +  unsigned int precision;
>
> I wonder if there is a technical reason to stick to HOST_WIDE_INTs?
> I'd say for efficiency HOST_WIDEST_FAST_INT would be more appropriate
> (to get a 32bit value on 32bit x86 for example).  I of course see that
> conversion to/from HOST_WIDE_INT is an important operation
> that would get slightly more complicated.
>
> Maybe just quickly checking the code generated on 32bit x86 for
> HOST_WIDE_INT vs. HOST_WIDEST_FAST_INT tells us whether
> it's worth considering (it would be bad if each add/multiply would
> end up calling to libgcc for example - I know that doesn't happen
> for x86, but maybe it would happen for an arm hosted gcc
> targeting x86_64?)
This is an interesting point.   my guess is that it is unlikely to be 
worth the work.
consider add:    most machines have add with carry and well written 32 
bit ports would have used an add with carry sequence rather than making 
the libcall.   If i rewrite wide-int in terms of host_fastest_int, then 
i have to do some messy code to compute the carry which is unlikely to 
translate into the proper carry instructions.   Not to mention the cost 
overhead of converting to and from HFI given that gcc is written almost 
entirely using HWIs.

I thought about the possible idea of just converting the mul and div 
functions.   This would be easy because i already reblock them into 
HOST_WIDE_HALF_INTs to do the math.    I could just do a different 
reblocking.   However, i think that it is unlikely that doing this would 
ever show up on anyone's performance counts.   Either way you do the 
same number of multiply instructions, it is just the subroutine wrapper 
that could possibly go away.

> +  enum ShiftOp {
> +    NONE,
> +    /* There are two uses for the wide-int shifting functions.  The
> +       first use is as an emulation of the target hardware.  The
> +       second use is as service routines for other optimizations.  The
> +       first case needs to be identified by passing TRUNC as the value
> +       of ShiftOp so that shift amount is properly handled according to the
> +       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
> +       amount is always truncated by the bytesize of the mode of
> +       THIS.  */
> +    TRUNC
> +  };
>
> double-int simply honors SHIFT_COUNT_TRUNCATED.  Why differ
> from that (and thus change behavior in existing code - not sure if you
> do that with introducing wide-int)?
I believe that GCC is supposed to be a little schizophrenic here, at 
least according to the doc.    when it is doing its own math it is 
defined to use SHIFT_COUNT_TRUNCATED, but when it is doing math for the 
program it is supposed to honor what the port does.   The idea is that 
you pass in TRUNC when you want to have the shift op do what the port 
does.   Again, this goes back to an insistence that the optimizations 
are just doing what the machine would do, only earlier.

> +  enum SignOp {
> +    /* Many of the math functions produce different results depending
> +       on if they are SIGNED or UNSIGNED.  In general, there are two
> +       different functions, whose names are prefixed with an 'S" and
> +       or an 'U'.  However, for some math functions there is also a
> +       routine that does not have the prefix and takes an SignOp
> +       parameter of SIGNED or UNSIGNED.  */
> +    SIGNED,
> +    UNSIGNED
> +  };
>
> You seem to insist on that.  It should propagate to the various parts
> of the compiler that have settled for the 'uns' integer argument.
> Having one piece behave different is just weird.  I suppose I will
> find code like
>
>      wi.ext (prec, uns ? UNSIGNED : SIGNED)
>
> in your conversion?
this has been resolved on another thread.
> +  static wide_int from_shwi (HOST_WIDE_INT op0,
> +                            unsigned int precision, bool *overflow = 0);
>
> +  if (precision < HOST_BITS_PER_WIDE_INT)
> +    {
> +      HOST_WIDE_INT t = sext_hwi (op0, precision);
> +      if (t != op0 && overflow)
> +       *overflow = true;
> +      op0 = t;
> +    }
>
> Hm.  I'd say input values should be properly extended already (we certainly
> expect that from RTL or tree constants).  So we might want to assert the
> above instead of tracking it via *overflow.
>
> +  static wide_int from_array (const HOST_WIDE_INT* op0,
> +                             unsigned int len,
> +                             unsigned int precision, bool need_canon = true);
> +  inline static wide_int from_array (const HOST_WIDE_INT* op0,
> +                                    unsigned int len,
> +                                    enum machine_mode mode);
> +  inline static wide_int from_array (const HOST_WIDE_INT* op0,
> +                                    unsigned int len,
> +                                    const_tree type);
>
> I still don't like the overloads precision vs. machine_mode vs. tree type.
> It's much more explanative what you specify here if you write
>
>    from_array (&x, len, GET_MODE_PRECISION (mode))
>
> instead of
>
>    from_array (&x, len, mode)
>
> and it's not that much more typing either.
>
> +  static wide_int from_double_int (double_int,
> +                                  unsigned int precision);
> +  inline static wide_int from_double_int (double_int, enum machine_mode);
>
> this one would lack the tree type overload (I of course think it has an
> excessive overload for machine_mode).
>
> +  inline HOST_WIDE_INT to_shwi (unsigned int prec = 0) const;
> +  inline unsigned HOST_WIDE_INT to_uhwi (unsigned int prec = 0) const;
>
> this is
>
>     wi.sext (prec);
>     wi.to_shwi ();
>
> which is less odd than handling prec == 0 specially.
>
> +  static wide_int max_value (unsigned int prec,
> +                            unsigned int precision, SignOp sgn);
>
> two precisions - ugh ;)  In some places having to have a precision is ugly :/
this is really necessary, unfortunately.   though perhaps i can 
rearrange the operands so that one of them can be defaulted.     The 
problem is that in vrp you want to know the max value of some small 
precision but you want that value to be expressed as a number in a 
larger precision.   outside of tree-vrp, the rest of the compiler only 
uses one precision

> +  inline static wide_int minus_one (unsigned int prec);
> +  inline static wide_int zero (unsigned int prec);
> +  inline static wide_int one (unsigned int prec);
> +  inline static wide_int two (unsigned int prec);
>
> here as well.  I see two (1) properly truncates the value to zero ;)
> It just comes to my mind that these could have "arbitrary" precision.
> "arbitrary" == MAX_SIZE * HOST_BITS_PER_WIDE_INT.  Which
> would get us back to mixed precision operations ...
these are now pretty rarely used since constants almost always appear as 
the second operand of a binary operation.    but the first operand has 
to convey the precision.
> +  /* Printing functions.  */
> +
> +  void print_dec (char *buf, SignOp sgn) const;
> +  void print_dec (FILE *file, SignOp sgn) const;
> +  void print_decs (char *buf) const;
> +  void print_decs (FILE *file) const;
> +  void print_decu (char *buf) const;
> +  void print_decu (FILE *file) const;
> +  void print_hex (char *buf) const;
> +  void print_hex (FILE *file) const;
>
> making those non-member functions would allow getting rid of stdio.h
> from wide-int.h (similar making the tree / rtx / mode argument methods
> either standalone or making them templates and externalizing the
> implementation to a separate template class would get rid of the
> rtl / tree dependency)
>
> +  inline bool neg_p () const;
>
> how can you test that?  wide-int doesn't have sign information.
>
> +bool
> +wide_int::neg_p () const
> +{
> +  return sign_mask () != 0;
>
> not exactly efficient either ...
>
> +HOST_WIDE_INT
> +wide_int::sign_mask () const
> +{
> +  int i = len - 1;
> +  if (precision < HOST_BITS_PER_WIDE_INT)
> +    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
> +           >> (HOST_BITS_PER_WIDE_INT - 1));
> +
> +  /* VRP appears to be badly broken and this is a very ugly fix.  */
> +  if (i >= 0)
> +    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
> +
> +  gcc_unreachable ();
> +#if 0
> +  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
> +#endif
> +}
>
> I can't see what's the "fix".  It seems to be equivalent to the commented out
> code.  Apart from not handling len == 0 for which you ICE then.
>
> Back to neg_p ... it computes wrong information.
> from_uwhi (-1, HOST_BITS_PER_WIDE_INT).neg_p () returns true.
>
> I suppose you want to rename it to msb () (implementing that efficiently
> and using it from sign_mask, too)
>
> +  template <typename T>
> +    inline bool gt_p (T c, SignOp sgn) const;
> +  template <typename T>
> +    inline bool gts_p (T c) const;
> +  template <typename T>
> +    inline bool gtu_p (T c) const;
>
> it's bad that we can't use the sign information we have available in almost
> all cases ... (where precision is not an exact multiple of
> HOST_BITS_PER_WIDE_INT
> and len == precision / HOST_BITS_PER_WIDE_INT).  It isn't hard to encode
> a sign - you just have to possibly waste a word of zeroes for positive
> values where at the moment precision is an exact multiple of
> HOST_BIST_PER_WIDE_INT and len == precision / HOST_BITS_PER_WIDE_INT.
> Which of course means that the encoding can be one word larger than
> maximally required by 'precision'.
>
> +  wide_int force_to_size (unsigned int precision, SignOp sgn) const;
> +  inline wide_int force_to_size (enum machine_mode mode, SignOp sgn) const;
> +  inline wide_int force_to_size (const_tree type) const;
> +  inline wide_int force_to_size (const_tree type, SignOp sgn) const;
> +
> +  inline wide_int sforce_to_size (enum machine_mode mode) const;
> +  inline wide_int sforce_to_size (const_tree type) const;
> +  inline wide_int zforce_to_size (enum machine_mode mode) const;
> +  inline wide_int zforce_to_size (const_tree type) const;
>
> too many overloads again
>
> Looking at
>
> +template <typename T>
> +wide_int
> +wide_int::operator & (T c) const
> +{
> +  wide_int result;
> +  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
> +  const HOST_WIDE_INT *s;
> +  int cl;
> +
> +  s = to_shwi2 (ws, &cl, c);
> +
>
> I see
>
> +  template <typename T>
> +  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int *l, T x)
> +  {
> +    s[0] = x;
> +    if (~(T)0 < (T)0
> ...
>
> +  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s
> ATTRIBUTE_UNUSED,
> +                                       int *l, const wide_int &y)
> +  {
> +    *l = y.len;
> ...
>
> I think you want to use template specialization here, not overloading.  Thus,
>
>    template <>
>    static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int
> *l, const wide_int &y)
>
> and adjust the HWI case to look like
>
>    template <typename T>
>    static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int
> *l, const T& x)
>
> you want to move that ~(T)0 < (T)0 check up to template substitution level
> to allow SFINAE to disable the template if that's not computable.
>
> +    s[0] = x;
> +    if (~(T)0 < (T)0
> +       || sizeof (T) < sizeof (HOST_WIDE_INT))
> +      {
> +       *l = 1;
> +      }
> +    else
> +      {
> +       s[1] = 0;
> +       *l = 2;
>
> that's only required if the MSB is set, otherwise it's not properly compressed
>
> +      }
> +    return s;
>
> hmm, looking at from_uhwi I see that you are adding the extra zero words
> as I suggested ... which means you _do_ have reliable sign information
> available (well, not for the case where len would end up bigger than MAX_LEN).
> So - can we simplify some things with that?  I can think of the ordered
> comparisons for example.  Also the encoding description should be
> clarified that there _is_ sign information available (and that len can be
> bigger than precision / HOST_BITS_PER_WIDE_INT).
i did all of this because it makes somethings easier and other things 
easier to talk about.   In particular it allows the binary operators to 
work properly with constants (thanks for the trick).

i did not do this because i have any interest in changing the compiler 
so that its math is
signed infinite precision.    I strongly do not want to go there. if you 
want to take my patches later and experiment with this, fine.   I do not 
want to be the person who chances people to use llvm because they all of 
a sudden start getting weird (but conforming to the c and c++ spec) 
results out of the optimizer.

In particular, others in the community consider it non conforming gimple 
to look at a value beyond the precision.   See the posting by iant about 
my question on 11/05/2012.




> Returning to to_shwi2 (odd name, btw):
>
> +       /* Copy the result because it does not fit in two HWIs.  */
> +       s[0] = TREE_INT_CST_LOW (tcst);
> +       s[1] = TREE_INT_CST_HIGH (tcst);
> +       s[2] = 0;
> +       *l = 3;
> +       return s;
>
> ah, this is why you need the extra argument ;)  Btw, what happens
> when a proper encoding does not fit in MAX_LEN words?  That is,
> we'd need an extra zero word?
this is a hack that will die when the tree cst has a variable len 
array.   When that happens, this code becomes an unconditional pointer 
copy.

> +  /* There should logically be an overload for rtl here, but it cannot
> +     be here because of circular include issues.  It is in rtl.h.  */
> +  static inline const HOST_WIDE_INT* to_shwi2
> +    (HOST_WIDE_INT *s ATTRIBUTE_UNUSED, int *l, rtx rcst);
>
> in rtl.c I suppose.  Btw, this is why I'm suggesting to defer implementation
> to a template - you can implement that outside of wide-int.h even without
> declaring the specialization here.
>
> Is there an accessible branch with the wide-int work?  I may be tempted
> to propose some changes in form of patches.  If not then I think the
> work is in a state that is suitable to put on a merge-branch.
i submitted all of the rtl work in the other patch and the first of the 
tree patches.   what i have is badly rotted so i was going to wait til i 
had a stable api to clean it up and post everything.
> +wide_int
> +wide_int::add (const wide_int &op1, SignOp sgn, bool *overflow) const
> +{
> ...
> +  /* Uncompress the rest.  */
> +  for (i = len; i < op1.len; i++)
> +    {
> +      o0 = val[i];
> +      o1 = mask1;
> +      x = o0 + o1 + carry;
> +      result.val[i] = x;
> +      old_carry = carry;
> +      carry = x < o0;
> +    }
> +  for (i = len; i < op1.len; i++)
> +    {
> +      o0 = mask0;
> +      o1 = op1.val[i];
> +      x = o0 + o1 + carry;
> +      result.val[i] = x;
> +      old_carry = carry;
> +      carry = x < o0;
> +    }
>
> Cut & paste error here I think.  at least one should run up to this->len, no?
no, if len is 3, the top one you can look at is 0
> And the first loop should run to min (len, op1.len) only.  How much
> testing coverage does the code have for "interesting" values?
> A standalone testing program will probably reveal such issues (due to
> the rich-ness of the current API covering everything will be hard :/)
>
> Looking at
>
> +HOST_WIDE_INT
> +wide_int::sign_mask () const
> +{
> +  int i = len - 1;
> +  if (precision < HOST_BITS_PER_WIDE_INT)
> +    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
> +           >> (HOST_BITS_PER_WIDE_INT - 1));
> +
> +  /* VRP appears to be badly broken and this is a very ugly fix.  */
> +  if (i >= 0)
> +    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
> +
> +  gcc_unreachable ();
> +#if 0
> +  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
> +#endif
> +}
>
> again - this looks like it does overly complicated work.  Our encoding
> of values guarantees that the following is correct:
>
> HOST_WIDE_INT
> wide_int::sign_mask () const
> {
>    if (val[len - 1] < 0)
>      return -1;
>    else
>      return 0;
> }
>
> I suppose quite some code can be simplified that calls sign_mask
> currently (thanks to the changed encoding).
>
> back to ::add ():
>
> +  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
> +  if (small_prec == 0)
> +    {
> +      if (sgn == wide_int::SIGNED)
> +       {
> +         if (((!(o0 ^ o1)) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
> +           *overflow = true;
>
> shouldn't this share code with the non-overflow add_large and simply
> do overflow detection conditional on overlflow being non-NULL?
> Because the add_large code seems to be correct with respect to
> the issues noted above ...
>
> + ex:
> +  result.canonize ();
> +  return result;
> +}
>
> canonizing is not strictly necessary - in fact it is unlikely to do
> something useful most of the time.  I'd say we should only
> canonize before building a tree or RTL with that representation.
> Note that canonize is wrong, too:
>
> +wide_int::canonize ()
> +{
> +  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
> +  int blocks_needed = BLOCKS_NEEDED (precision);
> +  HOST_WIDE_INT top;
> +  int i;
> +
> +  if (len > blocks_needed)
> +    len = blocks_needed;
>
> that will set a UHWI -1 to have len == 1, ignoring the extra needed
> zero word.  Thus, either BLOCKS_NEEDED is broken or its
> uses need to be audited.
>
> +
> +  /* Clean up the top bits for any mode that is not a multiple of a HWI.  */
> +  if (len == blocks_needed && small_prec)
> +    val[len - 1] = sext_hwi (val[len - 1], small_prec);
>
> That's not necessary.  By construction all arithmetic operations will
> preserve proper extension.  And you unconditionally sign-extend
> small precision "large" positive constants here which is even wrong
> (-1U, precision == 32, HWI == 64, original rep { 0x00..00fffff }, broken
> { 0xfff...fff } ).
>
> +  if (len == 1)
> +    return;
>
> in fact for len == 1 we should do nothing in this function from the start.
> Callers that also want to properly sign or zero extend the result value
> should do so using ext (), not abuse another implementation inside
> canonize () (which should only optimize the encoding).
>
> Ok, I'll stop reviewing here.  It's a lot better than before - thanks for
> doing the changes.
>
> I still like you to cut down the interface somewhat and _test_ what
> is remaining.  Put the code on a branch off trunk so I and others can
> produce patches against it.
>
> Thanks,
> Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* richard, i accidently pushed send rather than save,    the previous email was not finished,  just ignore it.
  2013-04-22 18:53                                                                                     ` Kenneth Zadeck
@ 2013-04-22 19:17                                                                                       ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-22 19:17 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

richard,

i pushed send rather than save, just ignore the last email i sent

sorry.


On 04/22/2013 01:59 PM, Kenneth Zadeck wrote:
> On 04/19/2013 09:31 AM, Richard Biener wrote:
>> +   number of elements of the vector that are in use.  When LEN *
>> +   HOST_BITS_PER_WIDE_INT < the precision, the value has been
>> +   compressed.  The values of the elements of the vector greater than
>> +   LEN - 1. are all equal to the highest order bit of LEN.
>>
>> equal to the highest order bit of element LEN - 1. ?
> Fixed, you are correct.
>
> I have gone thru the entire wide-int patch to clean this up.   The 
> bottom line is that if the precision is not a multiple of the size of 
> a HWI then everything above that precision is assumed to be identical 
> to the sign bit.
>
>> Especially _not_ equal to the precision - 1 bit of the value, correct?
> I do not understand your question here, because in the case talked 
> about above, the bit at precision - 1 would not have been explicitly 
> represented.
>
> Anyway,  i went thru this top part carefully and made many things 
> clearer.
>> +   The representation does not contain any information inherant about
>> +   signedness of the represented value, so it can be used to represent
>> +   both signed and unsigned numbers.   For operations where the results
>> +   depend on signedness (division, comparisons), the signedness must
>> +   be specified separately.  For operations where the signness
>> +   matters, one of the operands to the operation specifies either
>> +   wide_int::SIGNED or wide_int::UNSIGNED.
>>
>> The last sentence is somehow duplicated.
> fixed
>>
>> +   The numbers are stored as sign entended numbers as a means of
>> +   compression.  Leading HOST_WIDE_INTS that contain strings of either
>> +   -1 or 0 are removed as long as they can be reconstructed from the
>> +   top bit that is being represented.
>>
>> I'd put this paragraph before the one that talks about signedness, next
>> to the one that already talks about encoding.
> done
>> +   All constructors for wide_int take either a precision, an enum
>> +   machine_mode or tree_type.  */
>>
>> That's probably no longer true (I'll now check).
> yes you are correct
>
>> +class wide_int {
>> +  /* Internal representation.  */
>> +
>> +  /* VAL is set to a size that is capable of computing a full
>> +     multiplication on the largest mode that is represented on the
>> +     target.  The full multiplication is use by tree-vrp. tree-vpn
>> +     currently does a 2x largest mode by 2x largest mode yielding a 4x
>> +     largest mode result.  If operations are added that require larger
>> +     buffers, then VAL needs to be changed.  */
>> +  HOST_WIDE_INT val[WIDE_INT_MAX_ELTS];
>> +  unsigned short len;
>> +  unsigned int precision;
>>
>> I wonder if there is a technical reason to stick to HOST_WIDE_INTs?
>> I'd say for efficiency HOST_WIDEST_FAST_INT would be more appropriate
>> (to get a 32bit value on 32bit x86 for example).  I of course see that
>> conversion to/from HOST_WIDE_INT is an important operation
>> that would get slightly more complicated.
>>
>> Maybe just quickly checking the code generated on 32bit x86 for
>> HOST_WIDE_INT vs. HOST_WIDEST_FAST_INT tells us whether
>> it's worth considering (it would be bad if each add/multiply would
>> end up calling to libgcc for example - I know that doesn't happen
>> for x86, but maybe it would happen for an arm hosted gcc
>> targeting x86_64?)
> This is an interesting point.   my guess is that it is unlikely to be 
> worth the work.
> consider add:    most machines have add with carry and well written 32 
> bit ports would have used an add with carry sequence rather than 
> making the libcall.   If i rewrite wide-int in terms of 
> host_fastest_int, then i have to do some messy code to compute the 
> carry which is unlikely to translate into the proper carry 
> instructions.   Not to mention the cost overhead of converting to and 
> from HFI given that gcc is written almost entirely using HWIs.
>
> I thought about the possible idea of just converting the mul and div 
> functions.   This would be easy because i already reblock them into 
> HOST_WIDE_HALF_INTs to do the math.    I could just do a different 
> reblocking.   However, i think that it is unlikely that doing this 
> would ever show up on anyone's performance counts. Either way you do 
> the same number of multiply instructions, it is just the subroutine 
> wrapper that could possibly go away.
>
>> +  enum ShiftOp {
>> +    NONE,
>> +    /* There are two uses for the wide-int shifting functions. The
>> +       first use is as an emulation of the target hardware. The
>> +       second use is as service routines for other optimizations.  The
>> +       first case needs to be identified by passing TRUNC as the value
>> +       of ShiftOp so that shift amount is properly handled according 
>> to the
>> +       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
>> +       amount is always truncated by the bytesize of the mode of
>> +       THIS.  */
>> +    TRUNC
>> +  };
>>
>> double-int simply honors SHIFT_COUNT_TRUNCATED.  Why differ
>> from that (and thus change behavior in existing code - not sure if you
>> do that with introducing wide-int)?
> I believe that GCC is supposed to be a little schizophrenic here, at 
> least according to the doc.    when it is doing its own math it is 
> defined to use SHIFT_COUNT_TRUNCATED, but when it is doing math for 
> the program it is supposed to honor what the port does.   The idea is 
> that you pass in TRUNC when you want to have the shift op do what the 
> port does.   Again, this goes back to an insistence that the 
> optimizations are just doing what the machine would do, only earlier.
>
>> +  enum SignOp {
>> +    /* Many of the math functions produce different results depending
>> +       on if they are SIGNED or UNSIGNED.  In general, there are two
>> +       different functions, whose names are prefixed with an 'S" and
>> +       or an 'U'.  However, for some math functions there is also a
>> +       routine that does not have the prefix and takes an SignOp
>> +       parameter of SIGNED or UNSIGNED.  */
>> +    SIGNED,
>> +    UNSIGNED
>> +  };
>>
>> You seem to insist on that.  It should propagate to the various parts
>> of the compiler that have settled for the 'uns' integer argument.
>> Having one piece behave different is just weird.  I suppose I will
>> find code like
>>
>>      wi.ext (prec, uns ? UNSIGNED : SIGNED)
>>
>> in your conversion?
> this has been resolved on another thread.
>> +  static wide_int from_shwi (HOST_WIDE_INT op0,
>> +                            unsigned int precision, bool *overflow = 
>> 0);
>>
>> +  if (precision < HOST_BITS_PER_WIDE_INT)
>> +    {
>> +      HOST_WIDE_INT t = sext_hwi (op0, precision);
>> +      if (t != op0 && overflow)
>> +       *overflow = true;
>> +      op0 = t;
>> +    }
>>
>> Hm.  I'd say input values should be properly extended already (we 
>> certainly
>> expect that from RTL or tree constants).  So we might want to assert the
>> above instead of tracking it via *overflow.
>>
>> +  static wide_int from_array (const HOST_WIDE_INT* op0,
>> +                             unsigned int len,
>> +                             unsigned int precision, bool need_canon 
>> = true);
>> +  inline static wide_int from_array (const HOST_WIDE_INT* op0,
>> +                                    unsigned int len,
>> +                                    enum machine_mode mode);
>> +  inline static wide_int from_array (const HOST_WIDE_INT* op0,
>> +                                    unsigned int len,
>> +                                    const_tree type);
>>
>> I still don't like the overloads precision vs. machine_mode vs. tree 
>> type.
>> It's much more explanative what you specify here if you write
>>
>>    from_array (&x, len, GET_MODE_PRECISION (mode))
>>
>> instead of
>>
>>    from_array (&x, len, mode)
>>
>> and it's not that much more typing either.
>>
>> +  static wide_int from_double_int (double_int,
>> +                                  unsigned int precision);
>> +  inline static wide_int from_double_int (double_int, enum 
>> machine_mode);
>>
>> this one would lack the tree type overload (I of course think it has an
>> excessive overload for machine_mode).
>>
>> +  inline HOST_WIDE_INT to_shwi (unsigned int prec = 0) const;
>> +  inline unsigned HOST_WIDE_INT to_uhwi (unsigned int prec = 0) const;
>>
>> this is
>>
>>     wi.sext (prec);
>>     wi.to_shwi ();
>>
>> which is less odd than handling prec == 0 specially.
>>
>> +  static wide_int max_value (unsigned int prec,
>> +                            unsigned int precision, SignOp sgn);
>>
>> two precisions - ugh ;)  In some places having to have a precision is 
>> ugly :/
> this is really necessary, unfortunately.   though perhaps i can 
> rearrange the operands so that one of them can be defaulted. The 
> problem is that in vrp you want to know the max value of some small 
> precision but you want that value to be expressed as a number in a 
> larger precision.   outside of tree-vrp, the rest of the compiler only 
> uses one precision
>
>> +  inline static wide_int minus_one (unsigned int prec);
>> +  inline static wide_int zero (unsigned int prec);
>> +  inline static wide_int one (unsigned int prec);
>> +  inline static wide_int two (unsigned int prec);
>>
>> here as well.  I see two (1) properly truncates the value to zero ;)
>> It just comes to my mind that these could have "arbitrary" precision.
>> "arbitrary" == MAX_SIZE * HOST_BITS_PER_WIDE_INT.  Which
>> would get us back to mixed precision operations ...
> these are now pretty rarely used since constants almost always appear 
> as the second operand of a binary operation.    but the first operand 
> has to convey the precision.
>> +  /* Printing functions.  */
>> +
>> +  void print_dec (char *buf, SignOp sgn) const;
>> +  void print_dec (FILE *file, SignOp sgn) const;
>> +  void print_decs (char *buf) const;
>> +  void print_decs (FILE *file) const;
>> +  void print_decu (char *buf) const;
>> +  void print_decu (FILE *file) const;
>> +  void print_hex (char *buf) const;
>> +  void print_hex (FILE *file) const;
>>
>> making those non-member functions would allow getting rid of stdio.h
>> from wide-int.h (similar making the tree / rtx / mode argument methods
>> either standalone or making them templates and externalizing the
>> implementation to a separate template class would get rid of the
>> rtl / tree dependency)
>>
>> +  inline bool neg_p () const;
>>
>> how can you test that?  wide-int doesn't have sign information.
>>
>> +bool
>> +wide_int::neg_p () const
>> +{
>> +  return sign_mask () != 0;
>>
>> not exactly efficient either ...
>>
>> +HOST_WIDE_INT
>> +wide_int::sign_mask () const
>> +{
>> +  int i = len - 1;
>> +  if (precision < HOST_BITS_PER_WIDE_INT)
>> +    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
>> +           >> (HOST_BITS_PER_WIDE_INT - 1));
>> +
>> +  /* VRP appears to be badly broken and this is a very ugly fix.  */
>> +  if (i >= 0)
>> +    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
>> +
>> +  gcc_unreachable ();
>> +#if 0
>> +  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
>> +#endif
>> +}
>>
>> I can't see what's the "fix".  It seems to be equivalent to the 
>> commented out
>> code.  Apart from not handling len == 0 for which you ICE then.
>>
>> Back to neg_p ... it computes wrong information.
>> from_uwhi (-1, HOST_BITS_PER_WIDE_INT).neg_p () returns true.
>>
>> I suppose you want to rename it to msb () (implementing that efficiently
>> and using it from sign_mask, too)
>>
>> +  template <typename T>
>> +    inline bool gt_p (T c, SignOp sgn) const;
>> +  template <typename T>
>> +    inline bool gts_p (T c) const;
>> +  template <typename T>
>> +    inline bool gtu_p (T c) const;
>>
>> it's bad that we can't use the sign information we have available in 
>> almost
>> all cases ... (where precision is not an exact multiple of
>> HOST_BITS_PER_WIDE_INT
>> and len == precision / HOST_BITS_PER_WIDE_INT).  It isn't hard to encode
>> a sign - you just have to possibly waste a word of zeroes for positive
>> values where at the moment precision is an exact multiple of
>> HOST_BIST_PER_WIDE_INT and len == precision / HOST_BITS_PER_WIDE_INT.
>> Which of course means that the encoding can be one word larger than
>> maximally required by 'precision'.
>>
>> +  wide_int force_to_size (unsigned int precision, SignOp sgn) const;
>> +  inline wide_int force_to_size (enum machine_mode mode, SignOp sgn) 
>> const;
>> +  inline wide_int force_to_size (const_tree type) const;
>> +  inline wide_int force_to_size (const_tree type, SignOp sgn) const;
>> +
>> +  inline wide_int sforce_to_size (enum machine_mode mode) const;
>> +  inline wide_int sforce_to_size (const_tree type) const;
>> +  inline wide_int zforce_to_size (enum machine_mode mode) const;
>> +  inline wide_int zforce_to_size (const_tree type) const;
>>
>> too many overloads again
>>
>> Looking at
>>
>> +template <typename T>
>> +wide_int
>> +wide_int::operator & (T c) const
>> +{
>> +  wide_int result;
>> +  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
>> +  const HOST_WIDE_INT *s;
>> +  int cl;
>> +
>> +  s = to_shwi2 (ws, &cl, c);
>> +
>>
>> I see
>>
>> +  template <typename T>
>> +  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int 
>> *l, T x)
>> +  {
>> +    s[0] = x;
>> +    if (~(T)0 < (T)0
>> ...
>>
>> +  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s
>> ATTRIBUTE_UNUSED,
>> +                                       int *l, const wide_int &y)
>> +  {
>> +    *l = y.len;
>> ...
>>
>> I think you want to use template specialization here, not 
>> overloading.  Thus,
>>
>>    template <>
>>    static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int
>> *l, const wide_int &y)
>>
>> and adjust the HWI case to look like
>>
>>    template <typename T>
>>    static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int
>> *l, const T& x)
>>
>> you want to move that ~(T)0 < (T)0 check up to template substitution 
>> level
>> to allow SFINAE to disable the template if that's not computable.
>>
>> +    s[0] = x;
>> +    if (~(T)0 < (T)0
>> +       || sizeof (T) < sizeof (HOST_WIDE_INT))
>> +      {
>> +       *l = 1;
>> +      }
>> +    else
>> +      {
>> +       s[1] = 0;
>> +       *l = 2;
>>
>> that's only required if the MSB is set, otherwise it's not properly 
>> compressed
>>
>> +      }
>> +    return s;
>>
>> hmm, looking at from_uhwi I see that you are adding the extra zero words
>> as I suggested ... which means you _do_ have reliable sign information
>> available (well, not for the case where len would end up bigger than 
>> MAX_LEN).
>> So - can we simplify some things with that?  I can think of the ordered
>> comparisons for example.  Also the encoding description should be
>> clarified that there _is_ sign information available (and that len 
>> can be
>> bigger than precision / HOST_BITS_PER_WIDE_INT).
> i did all of this because it makes somethings easier and other things 
> easier to talk about.   In particular it allows the binary operators 
> to work properly with constants (thanks for the trick).
>
> i did not do this because i have any interest in changing the compiler 
> so that its math is
> signed infinite precision.    I strongly do not want to go there. if 
> you want to take my patches later and experiment with this, fine.   I 
> do not want to be the person who chances people to use llvm because 
> they all of a sudden start getting weird (but conforming to the c and 
> c++ spec) results out of the optimizer.
>
> In particular, others in the community consider it non conforming 
> gimple to look at a value beyond the precision.   See the posting by 
> iant about my question on 11/05/2012.
>
>
>
>
>> Returning to to_shwi2 (odd name, btw):
>>
>> +       /* Copy the result because it does not fit in two HWIs. */
>> +       s[0] = TREE_INT_CST_LOW (tcst);
>> +       s[1] = TREE_INT_CST_HIGH (tcst);
>> +       s[2] = 0;
>> +       *l = 3;
>> +       return s;
>>
>> ah, this is why you need the extra argument ;)  Btw, what happens
>> when a proper encoding does not fit in MAX_LEN words?  That is,
>> we'd need an extra zero word?
> this is a hack that will die when the tree cst has a variable len 
> array.   When that happens, this code becomes an unconditional pointer 
> copy.
>
>> +  /* There should logically be an overload for rtl here, but it cannot
>> +     be here because of circular include issues.  It is in rtl.h.  */
>> +  static inline const HOST_WIDE_INT* to_shwi2
>> +    (HOST_WIDE_INT *s ATTRIBUTE_UNUSED, int *l, rtx rcst);
>>
>> in rtl.c I suppose.  Btw, this is why I'm suggesting to defer 
>> implementation
>> to a template - you can implement that outside of wide-int.h even 
>> without
>> declaring the specialization here.
>>
>> Is there an accessible branch with the wide-int work?  I may be tempted
>> to propose some changes in form of patches.  If not then I think the
>> work is in a state that is suitable to put on a merge-branch.
> i submitted all of the rtl work in the other patch and the first of 
> the tree patches.   what i have is badly rotted so i was going to wait 
> til i had a stable api to clean it up and post everything.
>> +wide_int
>> +wide_int::add (const wide_int &op1, SignOp sgn, bool *overflow) const
>> +{
>> ...
>> +  /* Uncompress the rest.  */
>> +  for (i = len; i < op1.len; i++)
>> +    {
>> +      o0 = val[i];
>> +      o1 = mask1;
>> +      x = o0 + o1 + carry;
>> +      result.val[i] = x;
>> +      old_carry = carry;
>> +      carry = x < o0;
>> +    }
>> +  for (i = len; i < op1.len; i++)
>> +    {
>> +      o0 = mask0;
>> +      o1 = op1.val[i];
>> +      x = o0 + o1 + carry;
>> +      result.val[i] = x;
>> +      old_carry = carry;
>> +      carry = x < o0;
>> +    }
>>
>> Cut & paste error here I think.  at least one should run up to 
>> this->len, no?
> no, if len is 3, the top one you can look at is 0
>> And the first loop should run to min (len, op1.len) only.  How much
>> testing coverage does the code have for "interesting" values?
>> A standalone testing program will probably reveal such issues (due to
>> the rich-ness of the current API covering everything will be hard :/)
>>
>> Looking at
>>
>> +HOST_WIDE_INT
>> +wide_int::sign_mask () const
>> +{
>> +  int i = len - 1;
>> +  if (precision < HOST_BITS_PER_WIDE_INT)
>> +    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
>> +           >> (HOST_BITS_PER_WIDE_INT - 1));
>> +
>> +  /* VRP appears to be badly broken and this is a very ugly fix.  */
>> +  if (i >= 0)
>> +    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
>> +
>> +  gcc_unreachable ();
>> +#if 0
>> +  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
>> +#endif
>> +}
>>
>> again - this looks like it does overly complicated work.  Our encoding
>> of values guarantees that the following is correct:
>>
>> HOST_WIDE_INT
>> wide_int::sign_mask () const
>> {
>>    if (val[len - 1] < 0)
>>      return -1;
>>    else
>>      return 0;
>> }
>>
>> I suppose quite some code can be simplified that calls sign_mask
>> currently (thanks to the changed encoding).
>>
>> back to ::add ():
>>
>> +  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
>> +  if (small_prec == 0)
>> +    {
>> +      if (sgn == wide_int::SIGNED)
>> +       {
>> +         if (((!(o0 ^ o1)) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
>> +           *overflow = true;
>>
>> shouldn't this share code with the non-overflow add_large and simply
>> do overflow detection conditional on overlflow being non-NULL?
>> Because the add_large code seems to be correct with respect to
>> the issues noted above ...
>>
>> + ex:
>> +  result.canonize ();
>> +  return result;
>> +}
>>
>> canonizing is not strictly necessary - in fact it is unlikely to do
>> something useful most of the time.  I'd say we should only
>> canonize before building a tree or RTL with that representation.
>> Note that canonize is wrong, too:
>>
>> +wide_int::canonize ()
>> +{
>> +  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
>> +  int blocks_needed = BLOCKS_NEEDED (precision);
>> +  HOST_WIDE_INT top;
>> +  int i;
>> +
>> +  if (len > blocks_needed)
>> +    len = blocks_needed;
>>
>> that will set a UHWI -1 to have len == 1, ignoring the extra needed
>> zero word.  Thus, either BLOCKS_NEEDED is broken or its
>> uses need to be audited.
>>
>> +
>> +  /* Clean up the top bits for any mode that is not a multiple of a 
>> HWI.  */
>> +  if (len == blocks_needed && small_prec)
>> +    val[len - 1] = sext_hwi (val[len - 1], small_prec);
>>
>> That's not necessary.  By construction all arithmetic operations will
>> preserve proper extension.  And you unconditionally sign-extend
>> small precision "large" positive constants here which is even wrong
>> (-1U, precision == 32, HWI == 64, original rep { 0x00..00fffff }, broken
>> { 0xfff...fff } ).
>>
>> +  if (len == 1)
>> +    return;
>>
>> in fact for len == 1 we should do nothing in this function from the 
>> start.
>> Callers that also want to properly sign or zero extend the result value
>> should do so using ext (), not abuse another implementation inside
>> canonize () (which should only optimize the encoding).
>>
>> Ok, I'll stop reviewing here.  It's a lot better than before - thanks 
>> for
>> doing the changes.
>>
>> I still like you to cut down the interface somewhat and _test_ what
>> is remaining.  Put the code on a branch off trunk so I and others can
>> produce patches against it.
>>
>> Thanks,
>> Richard.
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-04 11:45                                                                                       ` Richard Biener
  2013-04-08  5:28                                                                                         ` Comments on the suggestion to use infinite precision math for wide int Kenneth Zadeck
@ 2013-04-22 21:39                                                                                         ` Richard Sandiford
  2013-04-23  0:35                                                                                           ` Richard Biener
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2013-04-22 21:39 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Richard Biener <richard.guenther@gmail.com> writes:
>> At the rtl level your idea does not work.   rtl constants do not have a mode
>> or type.
>
> Which is not true and does not matter.  I tell you why.  Quote:

It _is_ true, as long as you read "rtl constants" as "rtl integer constants" :-)

> +#if TARGET_SUPPORTS_WIDE_INT
> +
> +/* Match CONST_*s that can represent compile-time constant integers.  */
> +#define CASE_CONST_SCALAR_INT \
> +   case CONST_INT: \
> +   case CONST_WIDE_INT
>
> which means you are only replacing CONST_DOUBLE with wide-int.
> And _all_ CONST_DOUBLE have a mode.  Otherwise you'd have no
> way of creating the wide-int in the first place.

No, integer CONST_DOUBLEs have VOIDmode, just like CONST_INT.
Only floating-point CONST_DOUBLEs have a "real" mode.

>> I understand that this makes me vulnerable to the argument that we should
>> not let the rtl level ever dictate anything about the tree level, but the
>> truth is that a variable len rep is almost always used for big integers.
>> In our code, most constants of large types are small numbers.   (Remember i
>> got into this because the tree constant prop thinks that left shifting any
>> number by anything greater than 128 is always 0 and discovered that that was
>> just the tip of the iceberg.) But mostly i support the decision to canonize
>> numbers to the smallest number of HWIs because most of the algorithms to do
>> the math can be short circuited.    I admit that if i had to effectively
>> unpack most numbers to do the math, that the canonization would be a waste.
>> However, this is not really relevant to this conversation.   Yes, you could
>> get rid of the len, but this such a small part of picture.
>
> Getting rid of 'len' in the RTX storage was only a question of whether it
> is an efficient way to go forward.  And with considering to unify
> CONST_INTs and CONST_WIDE_INTs it is not.  And even for CONST_WIDE_INTs
> (which most of the time would be 2 HWI storage, as otherwise you'd use
> a CONST_INT) it would be an improvement.

FWIW, I don't really see any advantage in unifying CONST_INT and
CONST_WIDE_INT, for the reasons Kenny has already given.  CONST_INT
can represent a large majority of the integers and it is already a
fairly efficient representation.

It's more important that we don't pick a design that forces one
choice or the other.  And I think Kenny's patch achieves that goal,
because the choice is hidden behind macros and behind the wide_int
interface.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-22 21:39                                                                                         ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Richard Sandiford
@ 2013-04-23  0:35                                                                                           ` Richard Biener
  2013-04-23  6:47                                                                                             ` Richard Sandiford
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-23  0:35 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Richard Sandiford <rdsandiford@googlemail.com> wrote:

>Richard Biener <richard.guenther@gmail.com> writes:
>>> At the rtl level your idea does not work.   rtl constants do not
>have a mode
>>> or type.
>>
>> Which is not true and does not matter.  I tell you why.  Quote:
>
>It _is_ true, as long as you read "rtl constants" as "rtl integer
>constants" :-)
>
>> +#if TARGET_SUPPORTS_WIDE_INT
>> +
>> +/* Match CONST_*s that can represent compile-time constant integers.
> */
>> +#define CASE_CONST_SCALAR_INT \
>> +   case CONST_INT: \
>> +   case CONST_WIDE_INT
>>
>> which means you are only replacing CONST_DOUBLE with wide-int.
>> And _all_ CONST_DOUBLE have a mode.  Otherwise you'd have no
>> way of creating the wide-int in the first place.
>
>No, integer CONST_DOUBLEs have VOIDmode, just like CONST_INT.
>Only floating-point CONST_DOUBLEs have a "real" mode.

I stand corrected. Now that's one more argument for infinite precision constants, as the mode is then certainly provided by the operations similar to the sign. That is, the mode (or size, or precision) of 1 certainly does not matter.

>>> I understand that this makes me vulnerable to the argument that we
>should
>>> not let the rtl level ever dictate anything about the tree level,
>but the
>>> truth is that a variable len rep is almost always used for big
>integers.
>>> In our code, most constants of large types are small numbers.  
>(Remember i
>>> got into this because the tree constant prop thinks that left
>shifting any
>>> number by anything greater than 128 is always 0 and discovered that
>that was
>>> just the tip of the iceberg.) But mostly i support the decision to
>canonize
>>> numbers to the smallest number of HWIs because most of the
>algorithms to do
>>> the math can be short circuited.    I admit that if i had to
>effectively
>>> unpack most numbers to do the math, that the canonization would be a
>waste.
>>> However, this is not really relevant to this conversation.   Yes,
>you could
>>> get rid of the len, but this such a small part of picture.
>>
>> Getting rid of 'len' in the RTX storage was only a question of
>whether it
>> is an efficient way to go forward.  And with considering to unify
>> CONST_INTs and CONST_WIDE_INTs it is not.  And even for
>CONST_WIDE_INTs
>> (which most of the time would be 2 HWI storage, as otherwise you'd
>use
>> a CONST_INT) it would be an improvement.
>
>FWIW, I don't really see any advantage in unifying CONST_INT and
>CONST_WIDE_INT, for the reasons Kenny has already given.  CONST_INT
>can represent a large majority of the integers and it is already a
>fairly efficient representation.
>
>It's more important that we don't pick a design that forces one
>choice or the other.  And I think Kenny's patch achieves that goal,
>because the choice is hidden behind macros and behind the wide_int
>interface.

Not unifying const-int and double-int in the end would be odd.

Richard.

>Thanks,
>Richard


^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-23  0:35                                                                                           ` Richard Biener
@ 2013-04-23  6:47                                                                                             ` Richard Sandiford
  0 siblings, 0 replies; 217+ messages in thread
From: Richard Sandiford @ 2013-04-23  6:47 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Richard Biener <richard.guenther@gmail.com> writes:
> Richard Sandiford <rdsandiford@googlemail.com> wrote:
>>Richard Biener <richard.guenther@gmail.com> writes:
>>>> At the rtl level your idea does not work.   rtl constants do not
>>have a mode
>>>> or type.
>>>
>>> Which is not true and does not matter.  I tell you why.  Quote:
>>
>>It _is_ true, as long as you read "rtl constants" as "rtl integer
>>constants" :-)
>>
>>> +#if TARGET_SUPPORTS_WIDE_INT
>>> +
>>> +/* Match CONST_*s that can represent compile-time constant integers.
>> */
>>> +#define CASE_CONST_SCALAR_INT \
>>> +   case CONST_INT: \
>>> +   case CONST_WIDE_INT
>>>
>>> which means you are only replacing CONST_DOUBLE with wide-int.
>>> And _all_ CONST_DOUBLE have a mode.  Otherwise you'd have no
>>> way of creating the wide-int in the first place.
>>
>>No, integer CONST_DOUBLEs have VOIDmode, just like CONST_INT.
>>Only floating-point CONST_DOUBLEs have a "real" mode.
>
> I stand corrected. Now that's one more argument for infinite precision
> constants, as the mode is then certainly provided by the operations
> similar to the sign. That is, the mode (or size, or precision) of 1
> certainly does not matter.

I disagree.  Although CONST_INT and CONST_DOUBLE don't _store_ a mode,
they are always interpreted according to a particular mode.  It's just
that that mode has to be specified separately.  That's why so many
rtl functions have (enum machine_mode, rtx) pairs.

Infinite precision seems very alien to rtl, where everything is
interpreted according to a particular mode (whether that mode is
stored in the rtx or not).

For one thing, I don't see how infinite precision could work in an
environment where signedness often isn't defined.  E.g. if you optimise
an addition of two rtl constants, you don't know (and aren't supposed
to know) whether the values involved are "signed" or "unsigned".  With
fixed-precision arithmetic it doesn't matter, because both operands must
have the same precision, and because bits outside the precision are not
significant.  With infinite precision arithmetic, the choice carries
over to the next operation.  E.g., to take a 4-bit example, you don't
know when constructing a wide_int from an rtx whether 0b1000 represents
8 or -8.  But if you have no precision to say how many bits are significant,
you have to pick one.  Which do you choose?  And why should we have to
make a choice at all?  (Note that this is a different question to
whether the internal wide_int representation is sign-extending or not,
which is purely an implementation detail.  The same implementation
principle applies to CONST_INTs: the HWI in a CONST_INT is always
sign-extended from the msb of the represented value, although of course
the CONST_INT itself doesn't tell you which bit the msb is; that has to
be determined separately.)

A particular wide_int isn't, and IMO shouldn't be, inherently signed
or unsigned.  The rtl model is that signedness is a question of
interpretation rather than representation.  I realise trees are
different, because signedness is a property of the type rather
than operations on the type, but I still think fixed precision
works with both tree and rtl whereas infinite precision doesn't
work with rtl.

I also fear there are going to be lots of bugs where we forget to
truncate the result of an N-bit operation from "infinite" precision
to N bits before using it in the next operation (as per Kenny's ring
explanation).  With finite precision, and with all-important asserts
that the operands have consistent precisions, we shouldn't have any
hidden bugs like that.

If there are parts of gcc that really want to do infinite-precision
arithmetic, mpz_t ought to be as good as anything.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-22 15:21                                                                                       ` Richard Biener
@ 2013-04-23  8:11                                                                                         ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-23  8:11 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On 04/22/2013 08:20 AM, Richard Biener wrote:

>
> That said, a lot of my pushback is because I feel a little lonesome in this
> wide-int review and don't want to lone-some decide about that (generic)
> interface part as well.
yeh,  now sandiford is back from vacation so there are two of us to beat 
on you about your
how bad it would be to do infinite precision!!!!!!!

be careful what you wish for.

kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-17  3:41                                                                                   ` patch to fix constant math -5th patch, rtl Kenneth Zadeck
@ 2013-04-24 13:25                                                                                     ` Richard Biener
  2013-04-24 13:37                                                                                       ` Richard Sandiford
  2013-05-02 17:22                                                                                       ` Kenneth Zadeck
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Biener @ 2013-04-24 13:25 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

On Tue, Apr 16, 2013 at 10:17 PM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
> Here is a refreshed version of the rtl changes for wide-int.   the only
> change from the previous versions is that the wide-int binary operations
> have been simplified to use the new wide-int binary templates.

Looking for from_rtx calls (to see where we get the mode/precision from) I
see for example

-         o = rtx_to_double_int (outer);
-         i = rtx_to_double_int (inner);
-
-         m = double_int::mask (width);
-         i &= m;
-         m = m.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
-         i = i.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
-         o = o.and_not (m) | i;
-
+
+         o = (wide_int::from_rtx (outer, GET_MODE (SET_DEST (temp)))
+              .insert (wide_int::from_rtx (inner, GET_MODE (dest)),
+                       offset, width));

where I'd rather have the original code preserved as much as possible
and not introduce a new primitive wide_int::insert for this.  The conversion
and review process will be much more error-prone if we do multiple
things at once (and it might keep the wide_int initial interface leaner).

Btw, the wide_int::insert implementation doesn't assert anything about
the inputs precision.  Instead it reads

+  if (start + width >= precision)
+    width = precision - start;
+
+  mask = shifted_mask (start, width, false, precision);
+  tmp = op0.lshift (start, 0, precision, NONE);
+  result = tmp & mask;
+
+  tmp = and_not (mask);
+  result = result | tmp;

which eventually ends up performing everything in target precision.  So
we don't really care about the mode or precision of inner.

Then I see

diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index ad03a34..531a7c1 100644
@@ -180,6 +182,7 @@ typedef struct GTY(()) dw_val_struct {
       HOST_WIDE_INT GTY ((default)) val_int;
       unsigned HOST_WIDE_INT GTY ((tag
("dw_val_class_unsigned_const"))) val_unsigned;
       double_int GTY ((tag ("dw_val_class_const_double"))) val_double;
+      wide_int GTY ((tag ("dw_val_class_wide_int"))) val_wide;
       dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
       struct dw_val_die_union
        {

ick.  That makes dw_val_struct really large ... (and thus dw_attr_struct).
You need to make this a pointer to a wide_int at least.

-/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
+/* Return a constant integer corresponding to target reading
    GET_MODE_BITSIZE (MODE) bits from string constant STR.  */

 static rtx
 c_readstr (const char *str, enum machine_mode mode)
 {
-  HOST_WIDE_INT c[2];
+  wide_int c;
...
-  return immed_double_const (c[0], c[1], mode);
+
+  c = wide_int::from_array (tmp, len, mode);
+  return immed_wide_int_const (c, mode);
 }

err - what's this good for?  It doesn't look necessary as part of the initial
wide-int conversion at least.  (please audit your patches for such cases)

@@ -4994,12 +4999,12 @@ expand_builtin_signbit (tree exp, rtx target)

   if (bitpos < GET_MODE_BITSIZE (rmode))
     {
-      double_int mask = double_int_zero.set_bit (bitpos);
+      wide_int mask = wide_int::set_bit_in_zero (bitpos, rmode);

       if (GET_MODE_SIZE (imode) > GET_MODE_SIZE (rmode))
        temp = gen_lowpart (rmode, temp);
       temp = expand_binop (rmode, and_optab, temp,
-                          immed_double_int_const (mask, rmode),
+                          immed_wide_int_const (mask, rmode),
                           NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
   else

Likewise.  I suppose you remove immed_double_int_const but I see no
reason to do that.  It just makes your patch larger than necessary.

[what was the reason again to have TARGET_SUPPORTS_WIDE_INT at all?
It's supposed to be a no-op conversion, right?]

@@ -95,38 +95,9 @@ plus_constant (enum machine_mode mode, rtx x,
HOST_WIDE_INT c)

   switch (code)
     {
-    case CONST_INT:
-      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
-       {
-         double_int di_x = double_int::from_shwi (INTVAL (x));
-         double_int di_c = double_int::from_shwi (c);
-
-         bool overflow;
-         double_int v = di_x.add_with_sign (di_c, false, &overflow);
-         if (overflow)
-           gcc_unreachable ();
-
-         return immed_double_int_const (v, VOIDmode);
-       }
-
-      return GEN_INT (INTVAL (x) + c);
-
-    case CONST_DOUBLE:
-      {
-       double_int di_x = double_int::from_pair (CONST_DOUBLE_HIGH (x),
-                                                CONST_DOUBLE_LOW (x));
-       double_int di_c = double_int::from_shwi (c);
-
-       bool overflow;
-       double_int v = di_x.add_with_sign (di_c, false, &overflow);
-       if (overflow)
-         /* Sorry, we have no way to represent overflows this wide.
-            To fix, add constant support wider than CONST_DOUBLE.  */
-         gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT);
-
-       return immed_double_int_const (v, VOIDmode);
-      }
-
+    CASE_CONST_SCALAR_INT:
+      return immed_wide_int_const (wide_int::from_rtx (x, mode)
+                                  + wide_int::from_shwi (c, mode), mode);

you said you didn't want to convert CONST_INT to wide-int.  But the above
is certainly a lot less efficient than before - given your change to support
operator+ RTX even less efficient than possible.  The above also shows
three 'mode' arguments while one to immed_wide_int_const would be
enough (given it would truncate the arbitrary precision result from the
addition to modes precision).

That is, I see no reason to remove the CONST_INT case or the CONST_DOUBLE
case.  [why is the above not in any way guarded with TARGET_SUPPORTS_WIDE_INT?]

What happens with overflows in the wide-int case?  The double-int case
asserted that there is no overflow across 2 * hwi precision, the wide-int
case does not.  Still the wide-int case now truncates to 'mode' precision
while the CONST_DOUBLE case did not.

That's a change in behavior, no?  Effectively the code for CONST_INT
and CONST_DOUBLE did "arbitrary" precision arithmetic (up to the
precision they can encode) which wide-int changes.

Can we in such cases please to a preparatory patch and change the
CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
mode precision first?  What does wide-int do with VOIDmode mode inputs?
It seems to ICE on them for from_rtx and use garbage (0) for from_shwi.  Ugh.
Btw, plus_constant asserts that mode is either VOIDmode (I suppose semantically
do "arbitrary precision") or the same mode as the mode of x (I suppose
semantically do "mode precision").  Neither the current nor your implementation
seems to do something consistent here :/

So please, for those cases (I suppose there are many more, eventually
one of the reasons why you think that requiring a mode for all CONST_DOUBLEs
is impossible), can we massage the current code to 1) document what is
desired, 2) follow that specification with regarding to computation
mode / precision
and result mode / precision?

Thanks,
Richard.

> kenny
>

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 13:25                                                                                     ` Richard Biener
@ 2013-04-24 13:37                                                                                       ` Richard Sandiford
  2013-04-24 14:18                                                                                         ` Richard Biener
  2013-05-02 17:22                                                                                       ` Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2013-04-24 13:37 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Richard Biener <richard.guenther@gmail.com> writes:
> Can we in such cases please to a preparatory patch and change the
> CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
> mode precision first?

I'm not sure what you mean here.  CONST_INT HWIs are already sign-extended
from mode precision to HWI precision.  The 8-bit value 0xb10000000 must be
represented as (const_int -128); nothing else is allowed.  E.g. (const_int 128)
is not a valid QImode value on BITS_PER_UNIT==8 targets.

> What does wide-int do with VOIDmode mode inputs?
> It seems to ICE on them for from_rtx and use garbage (0) for from_shwi.  Ugh.

ICEing is right.  As mentioned before, every rtx constant has a mode,
whether it's stored in the rtx or not.  Callers must keep track of
what that mode is.

> Btw, plus_constant asserts that mode is either VOIDmode (I suppose
> semantically do "arbitrary precision")

No, not arbitrary precision.  It's always the precision specified
by the "mode" parameter.  The assert is:

  gcc_assert (GET_MODE (x) == VOIDmode || GET_MODE (x) == mode);

This is because GET_MODE always returns VOIDmode for CONST_INT and
CONST_DOUBLE integers.  The mode parameter is needed to tell us what
precision those CONST_INTs and CONST_DOUBLEs actually have, because
the rtx itself doesn't tell us.  The mode parameter serves no purpose
beyond that.

So if the rtx does specify a mode (everything except CONST_INT and
CONST_DOUBLE), the assert is making sure that the caller has correctly
tracked the rtx's mode and provided the right mode parameter.  The caller
must do that for all rtxes, it's just that we can't assert for it in the
CONST_INT and CONST_DOUBLE case, because the rtx has no mode to check
against.  If CONST_INT and CONST_DOUBLE did have a mode to check against,
there would be no need for the mode parameter at all.  Likewise there
would be no need for wide_int::from_rtx to have a mode parameter.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 13:37                                                                                       ` Richard Sandiford
@ 2013-04-24 14:18                                                                                         ` Richard Biener
  2013-04-24 14:34                                                                                           ` Richard Sandiford
  2013-04-24 14:57                                                                                           ` Kenneth Zadeck
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Biener @ 2013-04-24 14:18 UTC (permalink / raw)
  To: Richard Biener, Kenneth Zadeck, Mike Stump, gcc-patches,
	Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>> Can we in such cases please to a preparatory patch and change the
>> CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
>> mode precision first?
>
> I'm not sure what you mean here.  CONST_INT HWIs are already sign-extended
> from mode precision to HWI precision.  The 8-bit value 0xb10000000 must be
> represented as (const_int -128); nothing else is allowed.  E.g. (const_int 128)
> is not a valid QImode value on BITS_PER_UNIT==8 targets.

Yes, that's what I understand.  But consider you get a CONST_INT that is
_not_ a valid QImode value.  Current code simply trusts that it is, given
the context from ...

>> What does wide-int do with VOIDmode mode inputs?
>> It seems to ICE on them for from_rtx and use garbage (0) for from_shwi.  Ugh.
>
> ICEing is right.  As mentioned before, every rtx constant has a mode,
> whether it's stored in the rtx or not.  Callers must keep track of
> what that mode is.

... here.  So I see that both CONST_INT and CONST_DOUBLE get their
mode (or in wide-int speak precision) from the context.

Effectively a CONST_INT and CONST_DOUBLE is valid in multiple
modes and thus "arbitrary precision" with a limit set by the limit
of the encoding.

>> Btw, plus_constant asserts that mode is either VOIDmode (I suppose
>> semantically do "arbitrary precision")
>
> No, not arbitrary precision.  It's always the precision specified
> by the "mode" parameter.  The assert is:
>
>   gcc_assert (GET_MODE (x) == VOIDmode || GET_MODE (x) == mode);
>
> This is because GET_MODE always returns VOIDmode for CONST_INT and
> CONST_DOUBLE integers.  The mode parameter is needed to tell us what
> precision those CONST_INTs and CONST_DOUBLEs actually have, because
> the rtx itself doesn't tell us.  The mode parameter serves no purpose
> beyond that.

That doesn't make sense.  The only thing we could then do with the mode
is assert that the CONST_INT/CONST_DOUBLE is valid for mode.

mode does not constrain the result in any way, thus it happily produces
a CONST_INT (128) from QImode CONST_INT (127) + 1.  So, does the
caller of plus_constant have to verify the result is actually valid in the
mode it expects?  And what should it do if the result is not "valid"?

Given that we do not verify the input values and do not care for mode for
producing the output value the current behavior of plus_constant is to
compute in arbitrary precision.

wide-int changes the above to produce a different result (CONST_INT (-128)).
I'd rather not have this patch-set introduce such subtle differences.

I'd like to see the following:

1) strip away 'precision' from wide-int, make the sign/zero-extend operations
    that are now implicitely done explicit in the same way as done currently,
    thus, ...
2) do a more-or-less 1:1 conversion of existing double-int code.  double-int
    code already has all sign/zero-extensions that are required for correctness.

and after merging in wide-int

3) see what common code can be factored out (wide_int::insert and friends)
4) if seems fit, introduce a wide_int_with_precision class that provides
    a wrapper around wide_int and carries out operations in a fixed precision,
    doing sign-/zero-extends after each operation (I suppose not much code
    will be simplified by that)

before merging converting all targets is necessary - this isn't a part of
the infrastructure that can stand a partial conversion.  I suspect that
conversion of all targets is much easier after 2), especially if most
of the double-int interfaces are not removed but their implementation
changed to work on wide-ints (just as I mentioned for the immed_double_int_const
case, but likely not restricted to that - CONST_DOUBLE_LOW/HIGH
can be converted to code that asserts the encoding is sufficiently small
for example).  Thus,

5) piecewise remove legacy code dealing with CONST_DOUBLE

Btw, on 64bit hosts the rtx_def struct has 32bits padding before
the rtunion.  I think 32bit hosts are legacy now, so using that 32bits
padding by storing 'len' there will make space-efficient conversion
of CONST_INT possible.  Well, and avoids wasting another 32bits
of padding for CONST_WIDE on 64bit hosts.

> So if the rtx does specify a mode (everything except CONST_INT and
> CONST_DOUBLE), the assert is making sure that the caller has correctly
> tracked the rtx's mode and provided the right mode parameter.  The caller
> must do that for all rtxes, it's just that we can't assert for it in the
> CONST_INT and CONST_DOUBLE case, because the rtx has no mode to check
> against.  If CONST_INT and CONST_DOUBLE did have a mode to check against,
> there would be no need for the mode parameter at all.  Likewise there
> would be no need for wide_int::from_rtx to have a mode parameter.

constants do not have an intrinsic mode or precision.  They either do or
do not fit into a specific mode or precision.  If an operation is to be carried
out in a specific mode or precision I expect the result of the operation
fits into that specific mode or precision (which oddly isn't what it does now,
appearantly).

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 14:18                                                                                         ` Richard Biener
@ 2013-04-24 14:34                                                                                           ` Richard Sandiford
  2013-04-24 14:37                                                                                             ` Richard Biener
  2013-04-24 14:57                                                                                           ` Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2013-04-24 14:34 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Richard Biener <richard.guenther@gmail.com> writes:
> On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>> Can we in such cases please to a preparatory patch and change the
>>> CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
>>> mode precision first?
>>
>> I'm not sure what you mean here.  CONST_INT HWIs are already sign-extended
>> from mode precision to HWI precision.  The 8-bit value 0xb10000000 must be
>> represented as (const_int -128); nothing else is allowed.
>> E.g. (const_int 128)
>> is not a valid QImode value on BITS_PER_UNIT==8 targets.
>
> Yes, that's what I understand.  But consider you get a CONST_INT that is
> _not_ a valid QImode value.

But that's invalid :-)  It is not valid to call:

      plus_constant (QImode, GEN_INT (128), 1)

The point is that, even though it's invalid, we can't assert for it.

plus_constant is not for arbitrary precision arithmetic.  It's for
arithmetic in a given non-VOIDmode mode.

> Effectively a CONST_INT and CONST_DOUBLE is valid in multiple
> modes and thus "arbitrary precision" with a limit set by the limit
> of the encoding.

The same CONST_INT and CONST_DOUBLE can be shared for several constants
in different modes, yes, which is presumably what motivated making them
VOIDmode in the first place.  E.g. zero is const0_rtx for every integer
mode.  But in any given context, including plus_constant, the CONST_INT
or CONST_DOUBLE has a specific mode.

>>> Btw, plus_constant asserts that mode is either VOIDmode (I suppose
>>> semantically do "arbitrary precision")
>>
>> No, not arbitrary precision.  It's always the precision specified
>> by the "mode" parameter.  The assert is:
>>
>>   gcc_assert (GET_MODE (x) == VOIDmode || GET_MODE (x) == mode);
>>
>> This is because GET_MODE always returns VOIDmode for CONST_INT and
>> CONST_DOUBLE integers.  The mode parameter is needed to tell us what
>> precision those CONST_INTs and CONST_DOUBLEs actually have, because
>> the rtx itself doesn't tell us.  The mode parameter serves no purpose
>> beyond that.
>
> That doesn't make sense.  The only thing we could then do with the mode
> is assert that the CONST_INT/CONST_DOUBLE is valid for mode.

No, we have to generate a correct CONST_INT or CONST_DOUBLE result.
If we are adding 1 to a QImode (const_int 127), we must return
(const_int -128).  If we are adding 1 to HImode (const_int 127),
we must return (const_int 128).  However...

> mode does not constrain the result in any way, thus it happily produces
> a CONST_INT (128) from QImode CONST_INT (127) + 1.  So, does the
> caller of plus_constant have to verify the result is actually valid in the
> mode it expects?  And what should it do if the result is not "valid"?

...good spot.  That's a bug.  It should be:

      return gen_int_mode (INTVAL (x) + c, mode);

rather than:

      return GEN_INT (INTVAL (x) + c);

It's a long-standing bug, because in the old days we didn't have
the mode to hand.  It was missed when the mode was added.

But the mode is also used in:

      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
	{
	  double_int di_x = double_int::from_shwi (INTVAL (x));
	  double_int di_c = double_int::from_shwi (c);

	  bool overflow;
	  double_int v = di_x.add_with_sign (di_c, false, &overflow);
	  if (overflow)
	    gcc_unreachable ();

	  return immed_double_int_const (v, VOIDmode);
	}

which is deciding whether the result should be kept as a HWI even
in cases where the addition overflows.  It isn't arbitrary precision.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 14:34                                                                                           ` Richard Sandiford
@ 2013-04-24 14:37                                                                                             ` Richard Biener
  2013-04-24 14:53                                                                                               ` Richard Sandiford
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-24 14:37 UTC (permalink / raw)
  To: Richard Biener, Kenneth Zadeck, Mike Stump, gcc-patches,
	Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Wed, Apr 24, 2013 at 4:03 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>> On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford
>> <rdsandiford@googlemail.com> wrote:
>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>> Can we in such cases please to a preparatory patch and change the
>>>> CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
>>>> mode precision first?
>>>
>>> I'm not sure what you mean here.  CONST_INT HWIs are already sign-extended
>>> from mode precision to HWI precision.  The 8-bit value 0xb10000000 must be
>>> represented as (const_int -128); nothing else is allowed.
>>> E.g. (const_int 128)
>>> is not a valid QImode value on BITS_PER_UNIT==8 targets.
>>
>> Yes, that's what I understand.  But consider you get a CONST_INT that is
>> _not_ a valid QImode value.
>
> But that's invalid :-)  It is not valid to call:
>
>       plus_constant (QImode, GEN_INT (128), 1)
>
> The point is that, even though it's invalid, we can't assert for it.

Why can't we assert for it?

> plus_constant is not for arbitrary precision arithmetic.  It's for
> arithmetic in a given non-VOIDmode mode.
>
>> Effectively a CONST_INT and CONST_DOUBLE is valid in multiple
>> modes and thus "arbitrary precision" with a limit set by the limit
>> of the encoding.
>
> The same CONST_INT and CONST_DOUBLE can be shared for several constants
> in different modes, yes, which is presumably what motivated making them
> VOIDmode in the first place.  E.g. zero is const0_rtx for every integer
> mode.  But in any given context, including plus_constant, the CONST_INT
> or CONST_DOUBLE has a specific mode.
>
>>>> Btw, plus_constant asserts that mode is either VOIDmode (I suppose
>>>> semantically do "arbitrary precision")
>>>
>>> No, not arbitrary precision.  It's always the precision specified
>>> by the "mode" parameter.  The assert is:
>>>
>>>   gcc_assert (GET_MODE (x) == VOIDmode || GET_MODE (x) == mode);
>>>
>>> This is because GET_MODE always returns VOIDmode for CONST_INT and
>>> CONST_DOUBLE integers.  The mode parameter is needed to tell us what
>>> precision those CONST_INTs and CONST_DOUBLEs actually have, because
>>> the rtx itself doesn't tell us.  The mode parameter serves no purpose
>>> beyond that.
>>
>> That doesn't make sense.  The only thing we could then do with the mode
>> is assert that the CONST_INT/CONST_DOUBLE is valid for mode.
>
> No, we have to generate a correct CONST_INT or CONST_DOUBLE result.
> If we are adding 1 to a QImode (const_int 127), we must return
> (const_int -128).  If we are adding 1 to HImode (const_int 127),
> we must return (const_int 128).  However...
>
>> mode does not constrain the result in any way, thus it happily produces
>> a CONST_INT (128) from QImode CONST_INT (127) + 1.  So, does the
>> caller of plus_constant have to verify the result is actually valid in the
>> mode it expects?  And what should it do if the result is not "valid"?
>
> ...good spot.  That's a bug.  It should be:
>
>       return gen_int_mode (INTVAL (x) + c, mode);
>
> rather than:
>
>       return GEN_INT (INTVAL (x) + c);
>
> It's a long-standing bug, because in the old days we didn't have
> the mode to hand.  It was missed when the mode was added.
>
> But the mode is also used in:
>
>       if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
>         {
>           double_int di_x = double_int::from_shwi (INTVAL (x));
>           double_int di_c = double_int::from_shwi (c);
>
>           bool overflow;
>           double_int v = di_x.add_with_sign (di_c, false, &overflow);
>           if (overflow)
>             gcc_unreachable ();
>
>           return immed_double_int_const (v, VOIDmode);
>         }
>
> which is deciding whether the result should be kept as a HWI even
> in cases where the addition overflows.  It isn't arbitrary precision.

The above is wrong for SImode HOST_WIDE_INT and 0x7fffffff + 1
in the same way as the QImode case above.  It will produce
0x80000000.  The ICEing on "overflow" is odd as well as I'd have
expected twos-complement behavior which double-int, when
overflowing its 2 * HWI precision, provides.

I suppose the above should use immed_double_int_const (v, mode), too,
which oddly only ever truncates to mode for modes <= HOST_BITS_PER_WIDE_INT
via gen_int_mode.

Same of course for the code for CONST_DOUBLE.

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 14:37                                                                                             ` Richard Biener
@ 2013-04-24 14:53                                                                                               ` Richard Sandiford
  2013-04-24 15:07                                                                                                 ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2013-04-24 14:53 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Richard Biener <richard.guenther@gmail.com> writes:
> I suppose the above should use immed_double_int_const (v, mode), too,

In practice it doesn't matter, because...

> which oddly only ever truncates to mode for modes <= HOST_BITS_PER_WIDE_INT
> via gen_int_mode.

...right.  That's because there's not really any proper support for
non-power-of-2 modes.  Partial modes like PDI are specified by things like:

PARTIAL_INT_MODE (DI);

which is glaringly absent of any bit width.  So if the constant is big
enough to need 2 HWIs, it in practice must be exactly 2 HWIs wide.
One of the advantages of wide_int is that it allows us to relax this
restriction: we can have both (a) mode widths greater than
HOST_BITS_PER_WIDE_INT*2 and (b) mode widths that are greater than
HOST_BITS_PER_WIDE_INT while not being a multiple of it.

In other words, one of the reasons wide_int can't be exactly 1:1
in practice is because it is clearing out these mistakes (GEN_INT
rather than gen_int_mode) and missing features (non-power-of-2 widths).

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 14:18                                                                                         ` Richard Biener
  2013-04-24 14:34                                                                                           ` Richard Sandiford
@ 2013-04-24 14:57                                                                                           ` Kenneth Zadeck
  2013-04-24 15:49                                                                                             ` Richard Biener
  1 sibling, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-24 14:57 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On 04/24/2013 09:36 AM, Richard Biener wrote:
> On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>> Can we in such cases please to a preparatory patch and change the
>>> CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
>>> mode precision first?
>> I'm not sure what you mean here.  CONST_INT HWIs are already sign-extended
>> from mode precision to HWI precision.  The 8-bit value 0xb10000000 must be
>> represented as (const_int -128); nothing else is allowed.  E.g. (const_int 128)
>> is not a valid QImode value on BITS_PER_UNIT==8 targets.
> Yes, that's what I understand.  But consider you get a CONST_INT that is
> _not_ a valid QImode value.  Current code simply trusts that it is, given
> the context from ...
And the fact that it we have to trust but cannot verify is a severe 
problem at the rtl level that is not going to go away.    what i have 
been strongly objecting to is your idea that just because we cannot 
verify it, we can thus go change it in some completely different way 
(i.e. the infinite precision nonsense that you keep hitting us with) and 
it will all be ok.

I have three problems with this.

1) Even if we could do this, it gives us answers that are not what the 
programmer expects!!!!!!
Understand this!!!  Programmers expect the code to behave the same way 
if they optimize it or not.   If you do infinite precision arithmetic 
you get different answers than the machine may give you. While the C and 
C++ standards allow this, it is NOT desirable. While there are some 
optimizations that must make visible changes to be effective, this is 
certainly not the case with infinite precision math    Making the change 
to infinite precision math only because you think is pretty is NOT best 
practices and will only give GCC a bad reputation in the community.

Each programming language defines what it means to do constant 
arithmetic and by and large, our front ends do this the way they say.  
But once you go beyond that, you are squarely in the realm where an 
optimizer is expected to try to make the program run fast without 
changing the results.  Infinite precision math in the optimizations is 
visible in that A * B / C may get different answers between an infinite 
precision evaluation and one that is finite precision as specified by 
the types.  And all of this without any possible upside to the 
programmer.   Why would we want to drive people to use llvm?????   This 
is my primary objection.    If you ever gave any reason for infinite 
precision aside from that you consider it pretty, then i would consider 
it.    BUT THIS IS NOT WHAT PROGRAMMERS WANT!!!!

2) The rtl level of GCC does not follow best practices by today's 
standards.    It is quite fragile.     At this point, the best that can 
be said is that it generally seems to work.   What you are asking is for 
us to make the assumption that the code is in fact in better shape than 
it is.    I understand that in your mind, you are objecting to letting 
the back ends hold back something that you believe the middle ends 
should do, but the truth is that this is a bad idea for the middle ends.

3) If i am on a 32 bit machine and i say GEN_INT (0xffffffff), i get a 
32 bit word with 32 1s in it.   There is no other information. In 
particular there is no information that tells me was that a -1 or was 
that the largest positive integer.   We do not have GEN_INTS and a 
GEN_INTU, we just have GEN_INT.  Your desire is that we can take those 
32 bits and apply the lt_p function, not the ltu_p or lts_p function, 
but an lu_p function and use that to compare those 32 bits to 
something.   At the rtl level  there is simply not enough information 
there to sign extend this value.   This will never work without a major 
rewrite of the back ends.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 14:53                                                                                               ` Richard Sandiford
@ 2013-04-24 15:07                                                                                                 ` Richard Biener
  2013-04-24 15:13                                                                                                   ` Kenneth Zadeck
  2013-04-24 15:45                                                                                                   ` Richard Sandiford
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Biener @ 2013-04-24 15:07 UTC (permalink / raw)
  To: Richard Biener, Kenneth Zadeck, Mike Stump, gcc-patches,
	Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>> I suppose the above should use immed_double_int_const (v, mode), too,
>
> In practice it doesn't matter, because...
>
>> which oddly only ever truncates to mode for modes <= HOST_BITS_PER_WIDE_INT
>> via gen_int_mode.
>
> ...right.  That's because there's not really any proper support for
> non-power-of-2 modes.  Partial modes like PDI are specified by things like:
>
> PARTIAL_INT_MODE (DI);
>
> which is glaringly absent of any bit width.  So if the constant is big
> enough to need 2 HWIs, it in practice must be exactly 2 HWIs wide.

Ah, of course.

> One of the advantages of wide_int is that it allows us to relax this
> restriction: we can have both (a) mode widths greater than
> HOST_BITS_PER_WIDE_INT*2 and (b) mode widths that are greater than
> HOST_BITS_PER_WIDE_INT while not being a multiple of it.
>
> In other words, one of the reasons wide_int can't be exactly 1:1
> in practice is because it is clearing out these mistakes (GEN_INT
> rather than gen_int_mode) and missing features (non-power-of-2 widths).

Note that the argument should be about CONST_WIDE_INT here,
not wide-int.  Indeed CONST_WIDE_INT has the desired feature
and can be properly truncated/extended according to mode at the time we build it
via immed_wide_int_cst (w, mode).  I don't see the requirement that
wide-int itself is automagically providing that truncation/extension
(though it is a possibility, one that does not match existing behavior of
HWI for CONST_INT or double-int for CONST_DOUBLE).

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 15:07                                                                                                 ` Richard Biener
@ 2013-04-24 15:13                                                                                                   ` Kenneth Zadeck
  2013-04-24 15:45                                                                                                   ` Richard Sandiford
  1 sibling, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-24 15:13 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On 04/24/2013 10:42 AM, Richard Biener wrote:
> On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>> I suppose the above should use immed_double_int_const (v, mode), too,
>> In practice it doesn't matter, because...
>>
>>> which oddly only ever truncates to mode for modes <= HOST_BITS_PER_WIDE_INT
>>> via gen_int_mode.
>> ...right.  That's because there's not really any proper support for
>> non-power-of-2 modes.  Partial modes like PDI are specified by things like:
>>
>> PARTIAL_INT_MODE (DI);
>>
>> which is glaringly absent of any bit width.  So if the constant is big
>> enough to need 2 HWIs, it in practice must be exactly 2 HWIs wide.
> Ah, of course.
>
>> One of the advantages of wide_int is that it allows us to relax this
>> restriction: we can have both (a) mode widths greater than
>> HOST_BITS_PER_WIDE_INT*2 and (b) mode widths that are greater than
>> HOST_BITS_PER_WIDE_INT while not being a multiple of it.
>>
>> In other words, one of the reasons wide_int can't be exactly 1:1
>> in practice is because it is clearing out these mistakes (GEN_INT
>> rather than gen_int_mode) and missing features (non-power-of-2 widths).
> Note that the argument should be about CONST_WIDE_INT here,
> not wide-int.  Indeed CONST_WIDE_INT has the desired feature
> and can be properly truncated/extended according to mode at the time we build it
> via immed_wide_int_cst (w, mode).  I don't see the requirement that
> wide-int itself is automagically providing that truncation/extension
> (though it is a possibility, one that does not match existing behavior of
> HWI for CONST_INT or double-int for CONST_DOUBLE).
>
> Richard.
>
yes but you still have the problem with partial ints having no 
length.    Our plan was to be very careful and make sure that at no 
point were we doing anything that makes it harder to put modes in 
const_ints, but that is different from going thru everything and doing it.

Partially because of this discussion and some issues that you brought up 
with patch 4, i am removing the trick of being able to say 'wi + rtl' 
because there is no mode for the rtl.
i am leaving the 'wi + tree' because there is enough to info in the 
treecst to make this work.
but you are going to have to say something wi::add (mode, rtl)

see, i am willing to do things that work better in the tree world than 
in the rtl world.

kenny

>> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 15:07                                                                                                 ` Richard Biener
  2013-04-24 15:13                                                                                                   ` Kenneth Zadeck
@ 2013-04-24 15:45                                                                                                   ` Richard Sandiford
  2013-04-24 16:51                                                                                                     ` Richard Biener
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2013-04-24 15:45 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Richard Biener <richard.guenther@gmail.com> writes:
> On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> In other words, one of the reasons wide_int can't be exactly 1:1
>> in practice is because it is clearing out these mistakes (GEN_INT
>> rather than gen_int_mode) and missing features (non-power-of-2 widths).
>
> Note that the argument should be about CONST_WIDE_INT here,
> not wide-int.  Indeed CONST_WIDE_INT has the desired feature
> and can be properly truncated/extended according to mode at the time we build it
> via immed_wide_int_cst (w, mode).  I don't see the requirement that
> wide-int itself is automagically providing that truncation/extension
> (though it is a possibility, one that does not match existing behavior of
> HWI for CONST_INT or double-int for CONST_DOUBLE).

I agree it doesn't match the existing behaviour of HWI for CONST_INT or
double-int for CONST_DOUBLE, but I think that's very much a good thing.
The model for HWIs at the moment is that you have to truncate results
to the canonical form after every operation where it matters.  As you
proved in your earlier message about the plus_constant bug, that's easily
forgotten.  I don't think the rtl code is doing all CONST_INT arithmetic
on full HWIs because it wants to: it's doing it because that's the way
C/C++ arithmetic on primitive types works.  In other words, the current
CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N)
using a single primitive integer type.  wide_int gives us N-bit arithmetic
directly; no emulation is needed.

If your point is that an arbitrary-precision wide_int could be used by
other (non-rtl, and probably non-tree) clients, then I don't really
see the need.  We already have mpz_t for that.  What we don't have,
and what we IMO need, is something that performs N-bit arithmetic
for runtime N.  It seems better to have a single class that does
that for us (wide_int), rather than scatter N-bit emulation throughout
the codebase, which is what we do now.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 14:57                                                                                           ` Kenneth Zadeck
@ 2013-04-24 15:49                                                                                             ` Richard Biener
  2013-04-24 17:11                                                                                               ` Richard Sandiford
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-04-24 15:49 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Wed, Apr 24, 2013 at 4:35 PM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
> On 04/24/2013 09:36 AM, Richard Biener wrote:
>>
>> On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford
>> <rdsandiford@googlemail.com> wrote:
>>>
>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>
>>>> Can we in such cases please to a preparatory patch and change the
>>>> CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
>>>> mode precision first?
>>>
>>> I'm not sure what you mean here.  CONST_INT HWIs are already
>>> sign-extended
>>> from mode precision to HWI precision.  The 8-bit value 0xb10000000 must
>>> be
>>> represented as (const_int -128); nothing else is allowed.  E.g.
>>> (const_int 128)
>>> is not a valid QImode value on BITS_PER_UNIT==8 targets.
>>
>> Yes, that's what I understand.  But consider you get a CONST_INT that is
>> _not_ a valid QImode value.  Current code simply trusts that it is, given
>> the context from ...
>
> And the fact that it we have to trust but cannot verify is a severe problem
> at the rtl level that is not going to go away.    what i have been strongly
> objecting to is your idea that just because we cannot verify it, we can thus
> go change it in some completely different way (i.e. the infinite precision
> nonsense that you keep hitting us with) and it will all be ok.

Appearantly it is all ok because that's exactly what we have today (and
had for the last 25 years).  CONST_INT encodes infinite precision signed
values (with the complication that a QImode 0x80 isn't valid, thus all
modes are signed as well it seems).  CONST_DOUBLE encodes infinite
precision signed values as well.  Just the "infinite" is limited by the size
of the encoding, one and two HOST_WIDE_INTs.

The interpretation of those "infinite" precision constants is based on
the context (the operation mode of the operation we apply to a CONST_INT
or CONST_DOUBLE).  Thus CONST_INT and CONST_DOUBLE do
not have a mode or precision but VOIDmode so "different mode" 1
can be shared (which is probably the original reason of that design
decision).

> I have three problems with this.
>
> 1) Even if we could do this, it gives us answers that are not what the
> programmer expects!!!!!!
> Understand this!!!  Programmers expect the code to behave the same way if
> they optimize it or not.   If you do infinite precision arithmetic you get
> different answers than the machine may give you. While the C and C++
> standards allow this, it is NOT desirable. While there are some
> optimizations that must make visible changes to be effective, this is
> certainly not the case with infinite precision math    Making the change to
> infinite precision math only because you think is pretty is NOT best
> practices and will only give GCC a bad reputation in the community.

Note that as I tried to explain above this isn't a change.  _You_ are
proposing a change here!  Namely to associate a precision with a _constant_.
What precision does a '1' have?  What precision does a '12374' have?
It doesn't have any.  With this proposed change we will have the possibility
to explicitely program mismatches like

  simplify_binary_operation (PLUS_EXPR, HImode,
                                         wide_int_rtx (SImode, 27),
wide_int_rtx (QImode, 1))

even if _only_ the desired mode of the result matters!  Because given the
invariant that a wide-int is "valid" (it doesn't have bits outside of
its precision)
it's precision does no longer matter!

> Each programming language defines what it means to do constant arithmetic
> and by and large, our front ends do this the way they say.  But once you go
> beyond that, you are squarely in the realm where an optimizer is expected to
> try to make the program run fast without changing the results.  Infinite
> precision math in the optimizations is visible in that A * B / C may get
> different answers between an infinite precision evaluation and one that is
> finite precision as specified by the types.  And all of this without any
> possible upside to the programmer.   Why would we want to drive people to
> use llvm?????   This is my primary objection.    If you ever gave any reason
> for infinite precision aside from that you consider it pretty, then i would
> consider it.    BUT THIS IS NOT WHAT PROGRAMMERS WANT!!!!

Programming languages or prettiness is not in any way a reason to do
infinite precision math.  All-caps or pretty punctuation does not change that.

Infinite precision math is what we do now.  What I ask for is to make
separate changes separately.  You want larger and host independent
integer constants.  Fine - do that.  You want to change how we do
arithmetic?  Fine - do that.  But please separate the two.  (well, I'm
likely still going to object to the latter)

> 2) The rtl level of GCC does not follow best practices by today's standards.
> It is quite fragile.

It works quite well.

>     At this point, the best that can be said is that it
> generally seems to work.   What you are asking is for us to make the
> assumption that the code is in fact in better shape than it is.    I
> understand that in your mind, you are objecting to letting the back ends
> hold back something that you believe the middle ends should do, but the
> truth is that this is a bad idea for the middle ends.

I don't quite understand this.  What am I objecting to letting the back ends
hold back?

> 3) If i am on a 32 bit machine and i say GEN_INT (0xffffffff), i get a 32
> bit word with 32 1s in it.   There is no other information. In particular
> there is no information that tells me was that a -1 or was that the largest
> positive integer.   We do not have GEN_INTS and a GEN_INTU, we just have
> GEN_INT.  Your desire is that we can take those 32 bits and apply the lt_p
> function, not the ltu_p or lts_p function, but an lu_p function and use that
> to compare those 32 bits to something.   At the rtl level  there is simply
> not enough information there to sign extend this value.   This will never
> work without a major rewrite of the back ends.

Nono, I did not request that you get away with ltu_p or lts_p.  I said
it would be _possible_ to do that.  Currently (I just believe Richard here)
a positive QImode value 255 CONST_INT does not exist (well, it
does, but sign-extended and thus not distinguishable from -1) - correct?
Given the wide-int encoding in your last patch there is no reason to
disallow a positive QImode value 255 CONST_INT as we can perfectly
distinguish all values from -128 to 255 for QImode values as the encoding
uses extra bits to carry that information.  What is complicating things
is that to properly sign- or zero-extend a result according to the operation
mode you also need a desired signedness (that's an issue currently, too,
of course - nothing new here).  If you want a QImode add of 127 and 1
then you have to know whether the result is to be interpreted as
signed 8-bit value or unsigned 8-bit value.  Because that has an influence
on the encoding result (it doesn't matter if you view the 8 lower bits in the
"arbitrary precision" result 128 in twos-complement term of course).

Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 15:45                                                                                                   ` Richard Sandiford
@ 2013-04-24 16:51                                                                                                     ` Richard Biener
  2013-04-24 18:24                                                                                                       ` Richard Sandiford
  2013-04-25  8:38                                                                                                       ` Kenneth Zadeck
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Biener @ 2013-04-24 16:51 UTC (permalink / raw)
  To: Richard Biener, Kenneth Zadeck, Mike Stump, gcc-patches,
	Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>> On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
>> <rdsandiford@googlemail.com> wrote:
>>> In other words, one of the reasons wide_int can't be exactly 1:1
>>> in practice is because it is clearing out these mistakes (GEN_INT
>>> rather than gen_int_mode) and missing features (non-power-of-2 widths).
>>
>> Note that the argument should be about CONST_WIDE_INT here,
>> not wide-int.  Indeed CONST_WIDE_INT has the desired feature
>> and can be properly truncated/extended according to mode at the time we build it
>> via immed_wide_int_cst (w, mode).  I don't see the requirement that
>> wide-int itself is automagically providing that truncation/extension
>> (though it is a possibility, one that does not match existing behavior of
>> HWI for CONST_INT or double-int for CONST_DOUBLE).
>
> I agree it doesn't match the existing behaviour of HWI for CONST_INT or
> double-int for CONST_DOUBLE, but I think that's very much a good thing.
> The model for HWIs at the moment is that you have to truncate results
> to the canonical form after every operation where it matters.  As you
> proved in your earlier message about the plus_constant bug, that's easily
> forgotten.  I don't think the rtl code is doing all CONST_INT arithmetic
> on full HWIs because it wants to: it's doing it because that's the way
> C/C++ arithmetic on primitive types works.  In other words, the current
> CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N)
> using a single primitive integer type.  wide_int gives us N-bit arithmetic
> directly; no emulation is needed.

Ok, so what wide-int provides is integer values encoded in 'len' HWI
words that fit in 'precision' or more bits (and often in less).  wide-int
also provides N-bit arithmetic operations.  IMHO both are tied
too closely together.  A give constant doesn't really have a precision.
Associating one with it to give a precision to an arithmetic operation
looks wrong to me and are a source of mismatches.

What RTL currently has looks better to me - operations have
explicitely specified precisions.

> If your point is that an arbitrary-precision wide_int could be used by
> other (non-rtl, and probably non-tree) clients, then I don't really
> see the need.  We already have mpz_t for that.  What we don't have,
> and what we IMO need, is something that performs N-bit arithmetic
> for runtime N.  It seems better to have a single class that does
> that for us (wide_int), rather than scatter N-bit emulation throughout
> the codebase, which is what we do now.

mpz_t is not suitable here - it's way too expensive.  double-int
was the "suitable" bit for now, but given it's host dependency and
inability to handle larger ints (VRP ...) the ability to use wide-ints
for this looks appealing.

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 15:49                                                                                             ` Richard Biener
@ 2013-04-24 17:11                                                                                               ` Richard Sandiford
  2013-05-03 11:19                                                                                                 ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2013-04-24 17:11 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Richard Biener <richard.guenther@gmail.com> writes:
> On Wed, Apr 24, 2013 at 4:35 PM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> On 04/24/2013 09:36 AM, Richard Biener wrote:
>>>
>>> On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford
>>> <rdsandiford@googlemail.com> wrote:
>>>>
>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>
>>>>> Can we in such cases please to a preparatory patch and change the
>>>>> CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
>>>>> mode precision first?
>>>>
>>>> I'm not sure what you mean here.  CONST_INT HWIs are already
>>>> sign-extended
>>>> from mode precision to HWI precision.  The 8-bit value 0xb10000000 must
>>>> be
>>>> represented as (const_int -128); nothing else is allowed.  E.g.
>>>> (const_int 128)
>>>> is not a valid QImode value on BITS_PER_UNIT==8 targets.
>>>
>>> Yes, that's what I understand.  But consider you get a CONST_INT that is
>>> _not_ a valid QImode value.  Current code simply trusts that it is, given
>>> the context from ...
>>
>> And the fact that it we have to trust but cannot verify is a severe problem
>> at the rtl level that is not going to go away.    what i have been strongly
>> objecting to is your idea that just because we cannot verify it, we can thus
>> go change it in some completely different way (i.e. the infinite precision
>> nonsense that you keep hitting us with) and it will all be ok.
>
> Appearantly it is all ok because that's exactly what we have today (and
> had for the last 25 years).  CONST_INT encodes infinite precision signed
> values (with the complication that a QImode 0x80 isn't valid, thus all
> modes are signed as well it seems).

I think this is the fundamental disagreement.  Your last step doesn't
follow.  RTL integer modes are neither signed nor unsigned.  They are
just a collection of N bits.  The fact that CONST_INTs represent
smaller-than-HWI integers in sign-extended form is purely a represential
detail.  There are no semantics attached to it.  We could just as easily
have decided to extend with zeros or ones instead of sign bits.

Although the decision was made before my time, I'm pretty sure the
point of having a canonical representation (which happened to be sign
extension) was to make sure that any given rtl constant has only a
single representation.  It would be too confusing if a QImode 0x80 could
be represented as either (const_int 128) or (const_int -128) (would
(const_int 384) then also be OK?).

And that's the problem with using an infinite-precision wide_int.
If you directly convert a CONST_INT representation of 0x80 into a
wide_int, you will always get infinite-precision -128, thanks to the
CONST_INT canonicalisation rule.  But if you arrive at 0x80 though
arithmetic, you might get infinite-precision 128 instead.  These two
values would not compare equal.

> CONST_DOUBLE encodes infinite precision signed values as well.  Just
> the "infinite" is limited by the size of the encoding, one and two
> HOST_WIDE_INTs.

It encodes an N-bit integer.  It's just that (assuming non-power-of-2
modes) several N-bit integers (with varying N) can be encoded using the
same CONST_DOUBLE representation.  That might be what you meant, sorry,
and so might seem pedantic, but I wasn't sure.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 16:51                                                                                                     ` Richard Biener
@ 2013-04-24 18:24                                                                                                       ` Richard Sandiford
  2013-05-03 11:28                                                                                                         ` Richard Biener
  2013-04-25  8:38                                                                                                       ` Kenneth Zadeck
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2013-04-24 18:24 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Richard Biener <richard.guenther@gmail.com> writes:
> On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>> On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
>>> <rdsandiford@googlemail.com> wrote:
>>>> In other words, one of the reasons wide_int can't be exactly 1:1
>>>> in practice is because it is clearing out these mistakes (GEN_INT
>>>> rather than gen_int_mode) and missing features (non-power-of-2 widths).
>>>
>>> Note that the argument should be about CONST_WIDE_INT here,
>>> not wide-int.  Indeed CONST_WIDE_INT has the desired feature
>>> and can be properly truncated/extended according to mode at the time
>>> we build it
>>> via immed_wide_int_cst (w, mode).  I don't see the requirement that
>>> wide-int itself is automagically providing that truncation/extension
>>> (though it is a possibility, one that does not match existing behavior of
>>> HWI for CONST_INT or double-int for CONST_DOUBLE).
>>
>> I agree it doesn't match the existing behaviour of HWI for CONST_INT or
>> double-int for CONST_DOUBLE, but I think that's very much a good thing.
>> The model for HWIs at the moment is that you have to truncate results
>> to the canonical form after every operation where it matters.  As you
>> proved in your earlier message about the plus_constant bug, that's easily
>> forgotten.  I don't think the rtl code is doing all CONST_INT arithmetic
>> on full HWIs because it wants to: it's doing it because that's the way
>> C/C++ arithmetic on primitive types works.  In other words, the current
>> CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N)
>> using a single primitive integer type.  wide_int gives us N-bit arithmetic
>> directly; no emulation is needed.
>
> Ok, so what wide-int provides is integer values encoded in 'len' HWI
> words that fit in 'precision' or more bits (and often in less).  wide-int
> also provides N-bit arithmetic operations.  IMHO both are tied
> too closely together.  A give constant doesn't really have a precision.

I disagree.  All rtl objects have a precision.  REGs, MEMs, SYMBOL_REFs,
LABEL_REFs and CONSTs all have precisions, and the last three are
run-time constants.  Why should CONST_INT and CONST_DOUBLE be different?

See e.g. the hoops that cselib has to jump through:

/* We need to pass down the mode of constants through the hash table
   functions.  For that purpose, wrap them in a CONST of the appropriate
   mode.  */
static rtx
wrap_constant (enum machine_mode mode, rtx x)
{
  if ((!CONST_SCALAR_INT_P (x)) && GET_CODE (x) != CONST_FIXED)
    return x;
  gcc_assert (mode != VOIDmode);
  return gen_rtx_CONST (mode, x);
}

That is, cselib locally converts (const_int X) into (const:M (const_int X)),
purely so that it doesn't lose track of the CONST_INT's mode.
(const:M (const_int ...)) is invalid rtl elsewhere, but a necessary
hack here all the same.

> What RTL currently has looks better to me - operations have
> explicitely specified precisions.

But that isn't enough to determine the precision of all operands.
A classic case is ZERO_EXTEND.  Something like:

   (zero_extend:DI (reg:SI X))

is unambiguous.  But if you substitute (reg:SI X) with a CONST_INT,
the result becomes ambiguous.  E.g. we could end up with:

   (zero_extend:DI (const_int -1))

The ZERO_EXTEND operand still has SImode, but that fact is not explicit
in the rtl, and is certainly not explicit in the ZERO_EXTEND operation.
So if we just see the result above, we no longer know whether the result
should be (const_int 0xff), (const_int 0xffff), or what.  The same goes for:

   (zero_extend:DI (const_int 256))

where (const_int 0) and (const_int 256) are both potential results.

It's not just ZERO_EXTEND.  E.g.:

  (zero_extract:SI ...)

tells you that an SImode value is being extracted, but it doesn't tell
you what precision you're extracting from.  So for:

  (zero_extract:SI (const_int -1) (const_int X) (const_int 3))

how many 1 bits should be the result have?  Because of the sign-extension
canonicalisation, the answer depends on the precision of the (const_int -1),
which has now been lost.  If instead CONST_INTs were stored in zero-extended
form, the same ambiguity would apply to SIGN_EXTRACT.

This sort of thing has been a constant headache in rtl.  I can't stress
how much I feel it is _not_ better than recording the precision of
the constant :-)

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 16:51                                                                                                     ` Richard Biener
  2013-04-24 18:24                                                                                                       ` Richard Sandiford
@ 2013-04-25  8:38                                                                                                       ` Kenneth Zadeck
  2013-05-03 11:34                                                                                                         ` Richard Biener
  1 sibling, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-04-25  8:38 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On 04/24/2013 11:13 AM, Richard Biener wrote:
> On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford
> <rdsandiford@googlemail.com>  wrote:
>> Richard Biener<richard.guenther@gmail.com>  writes:
>>> On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
>>> <rdsandiford@googlemail.com>  wrote:
>>>> In other words, one of the reasons wide_int can't be exactly 1:1
>>>> in practice is because it is clearing out these mistakes (GEN_INT
>>>> rather than gen_int_mode) and missing features (non-power-of-2 widths).
>>> Note that the argument should be about CONST_WIDE_INT here,
>>> not wide-int.  Indeed CONST_WIDE_INT has the desired feature
>>> and can be properly truncated/extended according to mode at the time we build it
>>> via immed_wide_int_cst (w, mode).  I don't see the requirement that
>>> wide-int itself is automagically providing that truncation/extension
>>> (though it is a possibility, one that does not match existing behavior of
>>> HWI for CONST_INT or double-int for CONST_DOUBLE).
>> I agree it doesn't match the existing behaviour of HWI for CONST_INT or
>> double-int for CONST_DOUBLE, but I think that's very much a good thing.
>> The model for HWIs at the moment is that you have to truncate results
>> to the canonical form after every operation where it matters.  As you
>> proved in your earlier message about the plus_constant bug, that's easily
>> forgotten.  I don't think the rtl code is doing all CONST_INT arithmetic
>> on full HWIs because it wants to: it's doing it because that's the way
>> C/C++ arithmetic on primitive types works.  In other words, the current
>> CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N)
>> using a single primitive integer type.  wide_int gives us N-bit arithmetic
>> directly; no emulation is needed.
> Ok, so what wide-int provides is integer values encoded in 'len' HWI
> words that fit in 'precision' or more bits (and often in less).  wide-int
> also provides N-bit arithmetic operations.  IMHO both are tied
> too closely together.  A give constant doesn't really have a precision.
> Associating one with it to give a precision to an arithmetic operation
> looks wrong to me and are a source of mismatches.
>
> What RTL currently has looks better to me - operations have
> explicitely specified precisions.
I have tried very hard to make wide-int work very efficiently with both 
tree and rtl without biasing the rep towards either representation.  
Both rtl and trees constants have a precision.   In tree, constants are 
done better than in rtl because the tree really does have a field that 
is filled in that points to a type. However, that does not mean that rtl 
constants do not have a precision: currently you have to look around at 
the context to find the mode of a constant that is in your hand, but it 
is in fact always there.   At the rtl level, you can see the entire 
patch - we always find an appropriate mode.

In the future, this may change.   Wide-int moves one step closer in that 
ports that support it will not expect that double-ints never have a 
mode.   But that is a long way from having the mode attached.

What is not stored with the constant is a indication of the signedness. 
Unlike a desire to add modes to rtl constants, there is no one even 
thinking about the sign.   The sign is implicit in the operator, just as 
it is at the tree level.

So when i designed wide-int, i assumed that i could get precisions from 
the variables or at least "close to" them.

As far as the question of infinite precision, 99% of the uses of 
double-int today are "get in, do a single operation and get out". If 
this is all that we plan to do, then it does not really matter if it is 
infinite precision or not, because at both the rtl and tree level, we 
truncate on the way out.     However, the use of double-int accounts for 
only a small percentage of the math done in the compiler.   My wide-int 
port converts a substantial portion of the math from inline code that is 
guarded by checks to the precision against HOST_WIDE_BITS_PER_INT or 
calls to host_integerp.   The conversion of this code has substantial 
potential to expose the differences between the fixed precision and 
infinite precision representations.

The only justification that you have ever given for wanting to use 
infinite precision is that it is cleaner.   You have never directly 
addressed my point that it gives surprising answers except to say that 
the user would have to put in explicit intermediate truncations.    It 
is hard for me to imaging buggering up something as bad as having to put 
in explicit intermediate truncations.   When i write a * b / c, it 
should really look something like the expression.



>> If your point is that an arbitrary-precision wide_int could be used by
>> other (non-rtl, and probably non-tree) clients, then I don't really
>> see the need.  We already have mpz_t for that.  What we don't have,
>> and what we IMO need, is something that performs N-bit arithmetic
>> for runtime N.  It seems better to have a single class that does
>> that for us (wide_int), rather than scatter N-bit emulation throughout
>> the codebase, which is what we do now.
> mpz_t is not suitable here - it's way too expensive.  double-int
> was the "suitable" bit for now, but given it's host dependency and
> inability to handle larger ints (VRP ...) the ability to use wide-ints
> for this looks appealing.
and it is expensive why?   Because it is not tightly integrated into 
tree and rtl as you have fought me tooth and nail about?  Because the 
people who did mpz were idiots and you feel that i am god's gift to 
programming and will do a better job?   Or because infinite precision 
arithmetic might just be more expensive.

I vote for the last option.    Being able to exit out inline for the 
math that can be done in a HWI is actually a big win!!!!

> Richard.
>
>> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1
  2013-04-19 15:35                                                                                   ` Richard Biener
  2013-04-22  7:15                                                                                     ` Kenneth Zadeck
  2013-04-22 18:53                                                                                     ` Kenneth Zadeck
@ 2013-05-02 17:21                                                                                     ` Kenneth Zadeck
  2 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-05-02 17:21 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 25698 bytes --]

On 04/19/2013 09:31 AM, Richard Biener wrote:

Richi,

As you can see, i have done almost all of what you have recommended 
here. one thing that is different that was not addressed in this email. 
I changed the template that is used for the second operand for rtl so 
that rather than taking an rtl, it takes a pair <rtl, mode>. This means 
that i was able to add back the assertion checking that the second 
operand of binary operations is the same as for the first. I also moved 
the frag for the rtl templates into this patch set rather than the rtl 
patch set.

> +   number of elements of the vector that are in use.  When LEN *
> +   HOST_BITS_PER_WIDE_INT < the precision, the value has been
> +   compressed.  The values of the elements of the vector greater than
> +   LEN - 1. are all equal to the highest order bit of LEN.
>
> equal to the highest order bit of element LEN - 1. ?
Fixed, you are correct.

I have gone thru the entire wide-int patch to clean this up. The bottom 
line is that if the precision is not a multiple of the size of a HWI 
then everything above that precision is assumed to be identical to the 
sign bit.
> Especially _not_ equal to the precision - 1 bit of the value, correct?
I do not understand your question here, because in the case talked about 
above, the bit at precision - 1 would not have been explicitly represented.
> +   The representation does not contain any information inherant about
> +   signedness of the represented value, so it can be used to represent
> +   both signed and unsigned numbers.   For operations where the results
> +   depend on signedness (division, comparisons), the signedness must
> +   be specified separately.  For operations where the signness
> +   matters, one of the operands to the operation specifies either
> +   wide_int::SIGNED or wide_int::UNSIGNED.
>
> The last sentence is somehow duplicated.
fixed
> +   The numbers are stored as sign entended numbers as a means of
> +   compression.  Leading HOST_WIDE_INTS that contain strings of either
> +   -1 or 0 are removed as long as they can be reconstructed from the
> +   top bit that is being represented.
>
> I'd put this paragraph before the one that talks about signedness, next
> to the one that already talks about encoding.
done
> +   All constructors for wide_int take either a precision, an enum
> +   machine_mode or tree_type.  */
>
> That's probably no longer true (I'll now check).
yes you are correct
> +class wide_int {
> +  /* Internal representation.  */
> +
> +  /* VAL is set to a size that is capable of computing a full
> +     multiplication on the largest mode that is represented on the
> +     target.  The full multiplication is use by tree-vrp.  tree-vpn
> +     currently does a 2x largest mode by 2x largest mode yielding a 4x
> +     largest mode result.  If operations are added that require larger
> +     buffers, then VAL needs to be changed.  */
> +  HOST_WIDE_INT val[WIDE_INT_MAX_ELTS];
> +  unsigned short len;
> +  unsigned int precision;
>
> I wonder if there is a technical reason to stick to HOST_WIDE_INTs?
> I'd say for efficiency HOST_WIDEST_FAST_INT would be more appropriate
> (to get a 32bit value on 32bit x86 for example).  I of course see that
> conversion to/from HOST_WIDE_INT is an important operation
> that would get slightly more complicated.
>
> Maybe just quickly checking the code generated on 32bit x86 for
> HOST_WIDE_INT vs. HOST_WIDEST_FAST_INT tells us whether
> it's worth considering (it would be bad if each add/multiply would
> end up calling to libgcc for example - I know that doesn't happen
> for x86, but maybe it would happen for an arm hosted gcc
> targeting x86_64?)
This is an interesting point. my guess is that it is unlikely to be 
worth the work.
consider add: most machines have add with carry and well written 32 bit 
ports would have used an add with carry sequence rather than making the 
libcall. If i rewrite wide-int in terms of host_fastest_int, then i have 
to do some messy code to compute the carry which is unlikely to 
translate into the proper carry instructions. Not to mention the cost 
overhead of converting to and from HFI given that gcc is written almost 
entirely using HWIs.

I thought about the possible idea of just converting the mul and div 
functions. This would be easy because i already reblock them into 
HOST_WIDE_HALF_INTs to do the math. I could just do a different 
reblocking. However, i think that it is unlikely that doing this would 
ever show up on anyone's performance counts. Either way you do the same 
number of multiply instructions, it is just the subroutine wrapper that 
could possibly go away.
> +  enum ShiftOp {
> +    NONE,
> +    /* There are two uses for the wide-int shifting functions.  The
> +       first use is as an emulation of the target hardware.  The
> +       second use is as service routines for other optimizations.  The
> +       first case needs to be identified by passing TRUNC as the value
> +       of ShiftOp so that shift amount is properly handled according to the
> +       SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
> +       amount is always truncated by the bytesize of the mode of
> +       THIS.  */
> +    TRUNC
> +  };
>
> double-int simply honors SHIFT_COUNT_TRUNCATED.  Why differ
> from that (and thus change behavior in existing code - not sure if you
> do that with introducing wide-int)?
I believe that GCC is supposed to be a little schizophrenic here, at 
least according to the doc. when it is doing its own math it is defined 
to use SHIFT_COUNT_TRUNCATED, but when it is doing math for the program 
it is supposed to honor what the port does. The idea is that you pass in 
TRUNC when you want to have the shift op do what the port does. Again, 
this goes back to an insistence that the optimizations are just doing 
what the machine would do, only earlier.
> +  enum SignOp {
> +    /* Many of the math functions produce different results depending
> +       on if they are SIGNED or UNSIGNED.  In general, there are two
> +       different functions, whose names are prefixed with an 'S" and
> +       or an 'U'.  However, for some math functions there is also a
> +       routine that does not have the prefix and takes an SignOp
> +       parameter of SIGNED or UNSIGNED.  */
> +    SIGNED,
> +    UNSIGNED
> +  };
>
> You seem to insist on that.  It should propagate to the various parts
> of the compiler that have settled for the 'uns' integer argument.
> Having one piece behave different is just weird.  I suppose I will
> find code like
>
>      wi.ext (prec, uns ? UNSIGNED : SIGNED)
>
> in your conversion?
this has been handled in another thread.
> +  static wide_int from_shwi (HOST_WIDE_INT op0,
> +                            unsigned int precision, bool *overflow = 0);
>
> +  if (precision < HOST_BITS_PER_WIDE_INT)
> +    {
> +      HOST_WIDE_INT t = sext_hwi (op0, precision);
> +      if (t != op0 && overflow)
> +       *overflow = true;
> +      op0 = t;
> +    }
>
> Hm.  I'd say input values should be properly extended already (we certainly
> expect that from RTL or tree constants).  So we might want to assert the
> above instead of tracking it via *overflow.
see my discussion of overflow below. but you are basically correct.
> +  static wide_int from_array (const HOST_WIDE_INT* op0,
> +                             unsigned int len,
> +                             unsigned int precision, bool need_canon = true);
> +  inline static wide_int from_array (const HOST_WIDE_INT* op0,
> +                                    unsigned int len,
> +                                    enum machine_mode mode);
> +  inline static wide_int from_array (const HOST_WIDE_INT* op0,
> +                                    unsigned int len,
> +                                    const_tree type);
>
> I still don't like the overloads precision vs. machine_mode vs. tree type.
> It's much more explanative what you specify here if you write
>
>    from_array (&x, len, GET_MODE_PRECISION (mode))
>
> instead of
>
>    from_array (&x, len, mode)
>
> and it's not that much more typing either.
done
> +  static wide_int from_double_int (double_int,
> +                                  unsigned int precision);
> +  inline static wide_int from_double_int (double_int, enum machine_mode);
> this one would lack the tree type overload (I of course think it has an
> excessive overload for machine_mode).
done
> +  inline HOST_WIDE_INT to_shwi (unsigned int prec = 0) const;
> +  inline unsigned HOST_WIDE_INT to_uhwi (unsigned int prec = 0) const;
>
> this is
>
>     wi.sext (prec);
>     wi.to_shwi ();

> which is less odd than handling prec == 0 specially.
no it is not, wi.sext returns a wide-int, these return a HWI.
> +  static wide_int max_value (unsigned int prec,
> +                            unsigned int precision, SignOp sgn);
>
> two precisions - ugh ;)  In some places having to have a precision is ugly :/
i cleaned this up some. there are a few places where you want the min or 
max value to be represented in a larger precision than the precision 
that you are asking about. I reversed the last two args and made the 
last one take a default value so most of the time, you never see the 
second precision.
> +  inline static wide_int minus_one (unsigned int prec);
> +  inline static wide_int zero (unsigned int prec);
> +  inline static wide_int one (unsigned int prec);
> +  inline static wide_int two (unsigned int prec);
>
> here as well.  I see two (1) properly truncates the value to zero ;)
> It just comes to my mind that these could have "arbitrary" precision.
> "arbitrary" == MAX_SIZE * HOST_BITS_PER_WIDE_INT.  Which
> would get us back to mixed precision operations ...
>
you will end up with a wide-int that has been properly canonized, but it 
will not have a proper precision in it so it would not work to remove 
the precision. These are now rarely used since they are not needed as 
the second argument of binary functions.
> +  /* Printing functions.  */
> +
> +  void print_dec (char *buf, SignOp sgn) const;
> +  void print_dec (FILE *file, SignOp sgn) const;
> +  void print_decs (char *buf) const;
> +  void print_decs (FILE *file) const;
> +  void print_decu (char *buf) const;
> +  void print_decu (FILE *file) const;
> +  void print_hex (char *buf) const;
> +  void print_hex (FILE *file) const;
>
> making those non-member functions would allow getting rid of stdio.h
> from wide-int.h (similar making the tree / rtx / mode argument methods
> either standalone or making them templates and externalizing the
> implementation to a separate template class would get rid of the
> rtl / tree dependency)
done
> +  inline bool neg_p () const;
>
> how can you test that?  wide-int doesn't have sign information.
if you are asking this question, then you are assuming that the number 
is signed.
> +bool
> +wide_int::neg_p () const
> +{
> +  return sign_mask () != 0;
>
> not exactly efficient either ...
it is likely to be good enough.
> +HOST_WIDE_INT
> +wide_int::sign_mask () const
> +{
> +  int i = len - 1;
> +  if (precision < HOST_BITS_PER_WIDE_INT)
> +    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
> +           >> (HOST_BITS_PER_WIDE_INT - 1));
> +
> +  /* VRP appears to be badly broken and this is a very ugly fix.  */
> +  if (i >= 0)
> +    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
> +
> +  gcc_unreachable ();
> +#if 0
> +  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
> +#endif
> +}
>
> I can't see what's the "fix".  It seems to be equivalent to the commented out
> code.  Apart from not handling len == 0 for which you ICE then.
The problem is that tree-vrp is broken in a manner that it will not 
compile this function correctly. it has nothing to do using this 
function except that we cannot bootstrap the compiler with the function 
written in the straight forward manner.

if i write this function in the obvious way
/* Produce 0 or -1 that is the smear of the sign bit. */

HOST_WIDE_INT
wide_int::sign_mask () const
{
if (precision < HOST_BITS_PER_WIDE_INT)
return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
 >> (HOST_BITS_PER_WIDE_INT - 1));

return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
}

the function fails to bootstrap because there is a bug in vrp.
libbacktrace -DCLOOG_INT_GMP ../../gccWide/gcc/emit-rtl.c -o emit-rtl.o
In file included from ../../gccWide/gcc/rtl.h:31:0,
from ../../gccWide/gcc/emit-rtl.c:39:
../../gccWide/gcc/wide-int.h: In function ‘rtx_def* 
immed_wide_int_const(const wide_int&, machine_mode)Â’:
../../gccWide/gcc/wide-int.h:649:21: error: array subscript is below 
array bounds [-Werror=array-bounds]
return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);

so i hacked the code to fool vrp into shutting up. I was planning to put 
in a bugzilla after the code was in. But your eagle eye caught me on it.


> Back to neg_p ... it computes wrong information.
> from_uwhi (-1, HOST_BITS_PER_WIDE_INT).neg_p () returns true.
No, it produces exactly the correct answer. x.neg_p is short hand for 
x.lts_p (0).
the sign is not part of the number. the sign is an attribute of the 
operation which says how to interpret a particular bit pattern.



> I suppose you want to rename it to msb () (implementing that efficiently
> and using it from sign_mask, too)
>
> +  template <typename T>
> +    inline bool gt_p (T c, SignOp sgn) const;
> +  template <typename T>
> +    inline bool gts_p (T c) const;
> +  template <typename T>
> +    inline bool gtu_p (T c) const;
>
> it's bad that we can't use the sign information we have available in almost
> all cases ... (where precision is not an exact multiple of
> HOST_BITS_PER_WIDE_INT
> and len == precision / HOST_BITS_PER_WIDE_INT).  It isn't hard to encode
> a sign - you just have to possibly waste a word of zeroes for positive
> values where at the moment precision is an exact multiple of
> HOST_BIST_PER_WIDE_INT and len == precision / HOST_BITS_PER_WIDE_INT.
> Which of course means that the encoding can be one word larger than
> maximally required by 'precision'.
discussed elsewhere.
> +  wide_int force_to_size (unsigned int precision, SignOp sgn) const;
> +  inline wide_int force_to_size (enum machine_mode mode, SignOp sgn) const;
> +  inline wide_int force_to_size (const_tree type) const;
> +  inline wide_int force_to_size (const_tree type, SignOp sgn) const;
> +
> +  inline wide_int sforce_to_size (enum machine_mode mode) const;
> +  inline wide_int sforce_to_size (const_tree type) const;
> +  inline wide_int zforce_to_size (enum machine_mode mode) const;
> +  inline wide_int zforce_to_size (const_tree type) const;
>
> too many overloads again
i got rid of the type and mode overrides since you insist.
> Looking at
>
> +template <typename T>
> +wide_int
> +wide_int::operator & (T c) const
> +{
> +  wide_int result;
> +  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
> +  const HOST_WIDE_INT *s;
> +  int cl;
> +
> +  s = to_shwi2 (ws, &cl, c);
> +
>
> I see
>
> +  template <typename T>
> +  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int *l, T x)
> +  {
> +    s[0] = x;
> +    if (~(T)0 < (T)0
> ...
>
> +  static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s
> ATTRIBUTE_UNUSED,
> +                                       int *l, const wide_int &y)
> +  {
> +    *l = y.len;
> ...
>
> I think you want to use template specialization here, not overloading.  Thus,
>
>    template <>
>    static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int
> *l, const wide_int &y)
>
> and adjust the HWI case to look like
>
>    template <typename T>
>    static inline const HOST_WIDE_INT* to_shwi2 (HOST_WIDE_INT *s, int
> *l, const T& x)
>
> you want to move that ~(T)0 < (T)0 check up to template substitution level
> to allow SFINAE to disable the template if that's not computable.
>
> +    s[0] = x;
> +    if (~(T)0 < (T)0
> +       || sizeof (T) < sizeof (HOST_WIDE_INT))
> +      {
> +       *l = 1;
> +      }
> +    else
> +      {
> +       s[1] = 0;
> +       *l = 2;
>
> that's only required if the MSB is set, otherwise it's not properly compressed
>
> +      }
> +    return s;
done
> hmm, looking at from_uhwi I see that you are adding the extra zero words
> as I suggested ... which means you _do_ have reliable sign information
> available (well, not for the case where len would end up bigger than MAX_LEN).
> So - can we simplify some things with that?  I can think of the ordered
> comparisons for example.  Also the encoding description should be
> clarified that there _is_ sign information available (and that len can be
> bigger than precision / HOST_BITS_PER_WIDE_INT).
I actually got rid of the code below and one other place where i was 
adding the extra zeros, at least if it is beyond the precision. First, 
we should never be looking beyond the precision. Second, you cannot do 
this with rtl. For values stored in CONST_INTs. you get 64 bits and that 
is it.
> Returning to to_shwi2 (odd name, btw):
>
> +       /* Copy the result because it does not fit in two HWIs.  */
> +       s[0] = TREE_INT_CST_LOW (tcst);
> +       s[1] = TREE_INT_CST_HIGH (tcst);
> +       s[2] = 0;
> +       *l = 3;
> +       return s;
>
> ah, this is why you need the extra argument ;)  Btw, what happens
> when a proper encoding does not fit in MAX_LEN words?  That is,
> we'd need an extra zero word?
that never happens. This is what the patch (which has already gone in) 
that looked at the genmodes on the machine was all about. it computes 
that largest modes that can appear in a port and then multiplies that by 
4 to compute the amount of space to allocate on the stack. So 
WIDE_INT_MAX_ELTS is really always going to be large enough. Given that 
it is only very short lived stack space, this should not be an issue. 
However, this code is now gone because you never see past the precision 
so there is no reason to ever put in that word.
> +  /* There should logically be an overload for rtl here, but it cannot
> +     be here because of circular include issues.  It is in rtl.h.  */
> +  static inline const HOST_WIDE_INT* to_shwi2
> +    (HOST_WIDE_INT *s ATTRIBUTE_UNUSED, int *l, rtx rcst);
>
> in rtl.c I suppose.  Btw, this is why I'm suggesting to defer implementation
> to a template - you can implement that outside of wide-int.h even without
> declaring the specialization here.
it is in rtl.h so that it can be inlined and mostly go away. That code 
in the second of the three patches that were submitted together.

> Is there an accessible branch with the wide-int work?  I may be tempted
> to propose some changes in form of patches.  If not then I think the
> work is in a state that is suitable to put on a merge-branch.
At this point may things are still broken. I have all of the rtl changes 
and the first of the tree patches that i am keeping up to date as you 
have me make these changes. but the changes are too big to just keep 
pushing thru the whole mess. However, you can see how all of this works 
at the tree level by looking at the third patch.

> +wide_int
> +wide_int::add (const wide_int &op1, SignOp sgn, bool *overflow) const
> +{
> ...
> +  /* Uncompress the rest.  */
> +  for (i = len; i < op1.len; i++)
> +    {
> +      o0 = val[i];
> +      o1 = mask1;
> +      x = o0 + o1 + carry;
> +      result.val[i] = x;
> +      old_carry = carry;
> +      carry = x < o0;
> +    }
> +  for (i = len; i < op1.len; i++)
> +    {
> +      o0 = mask0;
> +      o1 = op1.val[i];
> +      x = o0 + o1 + carry;
> +      result.val[i] = x;
> +      old_carry = carry;
> +      carry = x < o0;
> +    }
>
> Cut & paste error here I think.  at least one should run up to this->len, no?
> And the first loop should run to min (len, op1.len) only.  How much
> testing coverage does the code have for "interesting" values?
> A standalone testing program will probably reveal such issues (due to
> the rich-ness of the current API covering everything will be hard :/)
when i started this, my model was double-int (yes, I did start with 
that) and there are several functions in that that do math and report 
overflow. So i added corresponding functions to wide-int. As it turns 
out, i never needed them because they turn out to only detect overflow 
if the value does not fit in two HWIs rather than as i had assumed, the 
value does not fit in the precision that the math is being done in. So 
they never got tested. They are now gone.

> Looking at
>
> +HOST_WIDE_INT
> +wide_int::sign_mask () const
> +{
> +  int i = len - 1;
> +  if (precision < HOST_BITS_PER_WIDE_INT)
> +    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
> +           >> (HOST_BITS_PER_WIDE_INT - 1));
> +
> +  /* VRP appears to be badly broken and this is a very ugly fix.  */
> +  if (i >= 0)
> +    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
> +
> +  gcc_unreachable ();
> +#if 0
> +  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
> +#endif
> +}
>
> again - this looks like it does overly complicated work.  Our encoding
> of values guarantees that the following is correct:
>
> HOST_WIDE_INT
> wide_int::sign_mask () const
> {
>    if (val[len - 1] < 0)
>      return -1;
>    else
>      return 0;
> }
>
> I suppose quite some code can be simplified that calls sign_mask
> currently (thanks to the changed encoding).
i think that guarantee is too strong a word, it is generally true but 
not always. The problem comes from the rtl constants. I cannot do the 
trick with the rtl constants. I only get to look at the bits under 
precision.


> back to ::add ():
>
> +  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
> +  if (small_prec == 0)
> +    {
> +      if (sgn == wide_int::SIGNED)
> +       {
> +         if (((!(o0 ^ o1)) & (x ^ o0)) >> (HOST_BITS_PER_WIDE_INT - 1))
> +           *overflow = true;
>
> shouldn't this share code with the non-overflow add_large and simply
> do overflow detection conditional on overlflow being non-NULL?
> Because the add_large code seems to be correct with respect to
> the issues noted above ...
not since i deleted the one that did the overflow.
> + ex:
> +  result.canonize ();
> +  return result;
> +}
>
> canonizing is not strictly necessary - in fact it is unlikely to do
> something useful most of the time.  I'd say we should only
> canonize before building a tree or RTL with that representation.
it is your "most of the time" that i have a problem with. Either the 
invariant is maintained that values are canonized or not. i have decided 
we consistently maintain that invariant.
> Note that canonize is wrong, too:
>
> +wide_int::canonize ()
> +{
> +  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
> +  int blocks_needed = BLOCKS_NEEDED (precision);
> +  HOST_WIDE_INT top;
> +  int i;
> +
> +  if (len > blocks_needed)
> +    len = blocks_needed;
>
> that will set a UHWI -1 to have len == 1, ignoring the extra needed
> zero word.  Thus, either BLOCKS_NEEDED is broken or its
> uses need to be audited.
i have removed the case from to_shwi for trees where i add the block 
with the extra 0 on top. The only invariant that is maintained is that 
there is nothing that can be looked at above the precision and with that 
one exception i am consistent.
> +
> +  /* Clean up the top bits for any mode that is not a multiple of a HWI.  */
> +  if (len == blocks_needed && small_prec)
> +    val[len - 1] = sext_hwi (val[len - 1], small_prec);
>
> That's not necessary.  By construction all arithmetic operations will
> preserve proper extension.  And you unconditionally sign-extend
> small precision "large" positive constants here which is even wrong
> (-1U, precision == 32, HWI == 64, original rep { 0x00..00fffff }, broken
> { 0xfff...fff } ).
that is not true. if you do a multiply, you get garbage in the top bits. 
This makes it easy to go to the other reps without canonizing. We only 
call the canon for certain operations that do not preserve the top bits 
properly.
> +  if (len == 1)
> +    return;
>
> in fact for len == 1 we should do nothing in this function from the start.
> Callers that also want to properly sign or zero extend the result value
> should do so using ext (), not abuse another implementation inside
> canonize () (which should only optimize the encoding).
>
> Ok, I'll stop reviewing here.  It's a lot better than before - thanks for
> doing the changes.
>
> I still like you to cut down the interface somewhat and _test_ what
> is remaining.  Put the code on a branch off trunk so I and others can
> produce patches against it.
Richard, this is going to be very hard to do. Let me explain why so we 
can figure out a path forward.
I can do about 95% of the stuff at the tree level by submitting small, 
easy to review, self contained patches where i convert one pass at a 
time. All of this leaves tree-cst in its current representation. I can 
get almost to the end, until i hit tree-vrp and the constant prop since 
they really do need a wider representation to do the infinite precision 
stuff that they do.

My plan was to convert everything: converting, testing, submitting and 
committing, one pass at a time until i get near the end, and then commit 
the last two patches and the change in rep at one time.

If i go the other route and make the big branch, then it will become 
very hard to tear small patches off to have easy review and testing. 
There are a lot of things in the current code base that expect tree-cst 
to be exactly two HWIs. I am not trying to hide anything from you, but 
you have made it clear that you want to see this is a series of bite 
sized chunks, not as one big blob and so i had planned to give it to you 
like that.


> Thanks,
> Richard.


[-- Attachment #2: p4-7.diff --]
[-- Type: text/x-patch, Size: 136133 bytes --]

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 903125e..25ed7bc 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -857,7 +857,7 @@ RTL_BASE_H = coretypes.h rtl.h rtl.def $(MACHMODE_H) reg-notes.def \
   insn-notes.def $(INPUT_H) $(REAL_H) statistics.h $(VEC_H) \
   $(FIXED_VALUE_H) alias.h $(HASHTAB_H)
 FIXED_VALUE_H = fixed-value.h $(MACHMODE_H) double-int.h
-RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h
+RTL_H = $(RTL_BASE_H) $(FLAGS_H) genrtl.h wide-int.h
 RTL_ERROR_H = rtl-error.h $(RTL_H) $(DIAGNOSTIC_CORE_H)
 READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
 PARAMS_H = params.h params.def
@@ -946,7 +946,7 @@ TREE_PRETTY_PRINT_H = tree-pretty-print.h $(PRETTY_PRINT_H)
 GIMPLE_PRETTY_PRINT_H = gimple-pretty-print.h $(TREE_PRETTY_PRINT_H)
 DIAGNOSTIC_CORE_H = diagnostic-core.h $(INPUT_H) bversion.h diagnostic.def
 DIAGNOSTIC_H = diagnostic.h $(DIAGNOSTIC_CORE_H) $(PRETTY_PRINT_H)
-DWARF2OUT_H = dwarf2out.h $(DWARF2_H)
+DWARF2OUT_H = dwarf2out.h $(DWARF2_H) wide-int.h
 C_PRETTY_PRINT_H = c-family/c-pretty-print.h $(PRETTY_PRINT_H) \
 	$(C_COMMON_H) $(TREE_H)
 SCEV_H = tree-scalar-evolution.h $(GGC_H) tree-chrec.h $(PARAMS_H)
@@ -1461,6 +1461,8 @@ OBJS = \
 	varpool.o \
 	vmsdbgout.o \
 	web.o \
+	wide-int.o \
+	wide-int-print.o \
 	xcoffout.o \
 	$(out_object_file) \
 	$(EXTRA_OBJS) \
@@ -2693,6 +2695,8 @@ targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
    tree-ssa-alias.h $(TREE_FLOW_H)
 common/common-targhooks.o : common/common-targhooks.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(INPUT_H) $(TM_H) $(COMMON_TARGET_H) common/common-targhooks.h
+wide-int.o: wide-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
+wide-int-print.o: wide-int-print.c wide-int-print.h wide-int.h
 
 bversion.h: s-bversion; @true
 s-bversion: BASE-VER
@@ -2861,10 +2865,10 @@ emit-rtl.o : emit-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(HASHTAB_H) $(TM_P_H) debug.h langhooks.h $(TREE_PASS_H) gt-emit-rtl.h \
    $(DF_H) $(PARAMS_H) $(TARGET_H)
 real.o : real.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
-   $(DIAGNOSTIC_CORE_H) $(TM_P_H) $(REAL_H) dfp.h realmpfr.h
+   $(DIAGNOSTIC_CORE_H) $(TM_P_H) $(REAL_H) dfp.h realmpfr.h wide-int.h
 realmpfr.o : realmpfr.c realmpfr.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(REAL_H) $(TREE_H)
 dfp.o : dfp.c dfp.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H)	$(TREE_H) \
-   $(TM_P_H) $(REAL_H) $(DECNUM_H)
+   $(TM_P_H) $(REAL_H) $(DECNUM_H) wide-int.h
 fixed-value.o: fixed-value.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) $(REAL_H) $(DIAGNOSTIC_CORE_H)
 jump.o : jump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
@@ -3752,6 +3756,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \
   $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c \
   $(srcdir)/dbxout.c \
+  $(srcdir)/wide-int.h \
   $(srcdir)/dwarf2out.h \
   $(srcdir)/dwarf2asm.c \
   $(srcdir)/dwarf2cfi.c \
@@ -3949,15 +3954,16 @@ CFLAGS-gengtype-parse.o += -DGENERATOR_FILE
 build/gengtype-parse.o: $(BCONFIG_H)
 
 gengtype-state.o build/gengtype-state.o: gengtype-state.c $(SYSTEM_H) \
-  gengtype.h errors.h double-int.h version.h $(HASHTAB_H) $(OBSTACK_H) \
-  $(XREGEX_H)
+  gengtype.h errors.h double-int.h version.h $(HASHTAB_H)    \
+  $(OBSTACK_H) $(XREGEX_H)
 gengtype-state.o: $(CONFIG_H)
 CFLAGS-gengtype-state.o += -DGENERATOR_FILE
 build/gengtype-state.o: $(BCONFIG_H)
-
+wide-int.h: $(GTM_H) $(TREE_H) hwint.h $(OPTIONS_H)			\
+  $(MACHMODE_H) double-int.h dumpfile.h $(REAL_H)
 gengtype.o build/gengtype.o : gengtype.c $(SYSTEM_H) gengtype.h 	\
-  rtl.def insn-notes.def errors.h double-int.h version.h $(HASHTAB_H) \
-  $(OBSTACK_H) $(XREGEX_H)
+  rtl.def insn-notes.def errors.h double-int.h version.h     		\
+  $(HASHTAB_H) $(OBSTACK_H) $(XREGEX_H)
 gengtype.o: $(CONFIG_H)
 CFLAGS-gengtype.o += -DGENERATOR_FILE
 build/gengtype.o: $(BCONFIG_H)
diff --git a/gcc/rtl.h b/gcc/rtl.h
index e9013ec..d019d9f 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_RTL_H
 #define GCC_RTL_H
 
+#include <utility>
 #include "statistics.h"
 #include "machmode.h"
 #include "input.h"
@@ -28,6 +29,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "fixed-value.h"
 #include "alias.h"
 #include "hashtab.h"
+#include "wide-int.h"
 #include "flags.h"
 
 /* Value used by some passes to "recognize" noop moves as valid
@@ -1309,6 +1385,55 @@ struct address_info {
   bool autoinc_p;
 };
 
+#ifndef GENERATOR_FILE
+
+/* Accessors for rtx_mode. */
+static inline rtx
+get_rtx (const rtx_mode_t p)
+{
+  return p.first;
+}
+
+static inline enum machine_mode
+get_mode (const rtx_mode_t p)
+{
+  return p.second;
+}
+
+/* Specialization of to_shwi2 function in wide-int.h for rtl.  This
+   cannot be in wide-int.h because of circular includes.  */
+template<>
+inline const HOST_WIDE_INT*
+wide_int::to_shwi2 (HOST_WIDE_INT *s ATTRIBUTE_UNUSED, 
+		    unsigned int *l, unsigned int *p,
+		    const rtx_mode_t& rp)
+{
+  const rtx rcst = get_rtx (rp);
+  enum machine_mode mode = get_mode (rp);
+  *p = GET_MODE_PRECISION (mode);
+
+  switch (GET_CODE (rcst))
+    {
+    case CONST_INT:
+      *l = 1;
+      return &INTVAL (rcst);
+      
+    case CONST_WIDE_INT:
+      *l = CONST_WIDE_INT_NUNITS (rcst);
+      return &CONST_WIDE_INT_ELT (rcst, 0);
+      
+    case CONST_DOUBLE:
+      *l = 2;
+      return &CONST_DOUBLE_LOW (rcst);
+      
+    default:
+      gcc_unreachable ();
+    }
+}
+
+#endif
+
+
 extern void init_rtlanal (void);
 extern int rtx_cost (rtx, enum rtx_code, int, bool);
 extern int address_cost (rtx, enum machine_mode, addr_space_t, bool);
diff --git a/gcc/wide-int-print.c b/gcc/wide-int-print.c
new file mode 100644
index 0000000..124b17a
--- /dev/null
+++ b/gcc/wide-int-print.c
@@ -0,0 +1,138 @@
+/* Printing operations with very long integers.
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hwint.h"
+#include "wide-int.h"
+#include "wide-int-print.h"
+
+/*
+ * public printing routines.
+ */
+
+#define BLOCKS_NEEDED(PREC) \
+  (((PREC) + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+
+void 
+print_dec (const wide_int &wi, char *buf, SignOp sgn)
+{
+  if (sgn == SIGNED)
+    print_decs (wi, buf);
+  else
+    print_decu (wi, buf);
+}
+
+void 
+print_dec (const wide_int &wi, FILE *file, SignOp sgn)
+{
+  if (sgn == SIGNED)
+    print_decs (wi, file);
+  else
+    print_decu (wi, file);
+}
+
+
+/* Try to print the signed self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+print_decs (const wide_int &wi, char *buf)
+{
+  if ((wi.get_precision () <= HOST_BITS_PER_WIDE_INT)
+      || (wi.get_len () == 1 && !wi.neg_p ()))
+    sprintf (buf, HOST_WIDE_INT_PRINT_DEC, wi.elt (0));
+  else
+    print_hex (wi, buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+print_decs (const wide_int &wi, FILE *file)
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decs (wi, buf);
+  fputs (buf, file);
+}
+
+/* Try to print the unsigned self in decimal to BUF if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+print_decu (const wide_int &wi, char *buf)
+{
+  if ((wi.get_precision () <= HOST_BITS_PER_WIDE_INT)
+      || (wi.get_len () == 1 && !wi.neg_p ()))
+    sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, wi.elt (0));
+  else
+    print_hex (wi, buf);
+}
+
+/* Try to print the signed self in decimal to FILE if the number fits
+   in a HWI.  Other print in hex.  */
+
+void 
+print_decu (const wide_int &wi, FILE *file)
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_decu (wi, buf);
+  fputs (buf, file);
+}
+
+void 
+print_hex (const wide_int &wi, char *buf)
+{
+  int i = wi.get_len ();
+
+  if (wi.zero_p ())
+    sprintf (buf, "0x");
+  else
+    {
+      if (wi.neg_p ())
+	{
+	  int j;
+	  /* If the number is negative, we may need to pad value with
+	     0xFFF...  because the leading elements may be missing and
+	     we do not print a '-' with hex.  */
+	  for (j = BLOCKS_NEEDED (wi.get_precision ()); j > i; j--)
+	    buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, (HOST_WIDE_INT) -1);
+	    
+	}
+      else
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_HEX, wi.elt (--i));
+      while (--i >= 0)
+	buf += sprintf (buf, HOST_WIDE_INT_PRINT_PADDED_HEX, wi.elt (i));
+    }
+}
+
+/* Print one big hex number to FILE.  Note that some assemblers may not
+   accept this for large modes.  */
+void 
+print_hex (const wide_int &wi, FILE *file)
+{
+  char buf[(2 * MAX_BITSIZE_MODE_ANY_INT / BITS_PER_UNIT) + 4];
+  print_hex (wi, buf);
+  fputs (buf, file);
+}
+
diff --git a/gcc/wide-int-print.h b/gcc/wide-int-print.h
new file mode 100644
index 0000000..f285c57
--- /dev/null
+++ b/gcc/wide-int-print.h
@@ -0,0 +1,37 @@
+/* Print wide integers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef WIDE_INT_PRINT_H
+#define WIDE_INT_PRINT_H
+
+#include <stdio.h>
+#include "wide-int.h"
+
+/* Printing functions.  */
+
+extern void print_dec (const wide_int &wi, char *buf, SignOp sgn);
+extern void print_dec (const wide_int &wi, FILE *file, SignOp sgn);
+extern void print_decs (const wide_int &wi, char *buf);
+extern void print_decs (const wide_int &wi, FILE *file);
+extern void print_decu (const wide_int &wi, char *buf);
+extern void print_decu (const wide_int &wi, FILE *file);
+extern void print_hex (const wide_int &wi, char *buf);
+extern void print_hex (const wide_int &wi, FILE *file);
+
+#endif /* WIDE_INT_PRINT_H */
diff --git a/gcc/wide-int.c b/gcc/wide-int.c
new file mode 100644
index 0000000..4853093
--- /dev/null
+++ b/gcc/wide-int.c
@@ -0,0 +1,2394 @@
+/* Operations with very long integers.  -*- C++ -*-
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hwint.h"
+#include "wide-int.h"
+#include "rtl.h"
+#include "tree.h"
+#include "dumpfile.h"
+
+/* This is the maximal size of the buffer needed for dump.  */
+const int MAX_SIZE = 4 * (MAX_BITSIZE_MODE_ANY_INT / 4
+		     + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT + 32);
+
+/*
+ * Internal utilities.
+ */
+
+/* Quantities to deal with values that hold half of a wide int.  Used
+   in multiply and divide.  */
+#define HALF_INT_MASK (((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1)
+
+#define BLOCK_OF(TARGET) ((TARGET) / HOST_BITS_PER_WIDE_INT)
+#define BLOCKS_NEEDED(PREC) \
+  (((PREC) + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+#define SIGN_MASK(X) (((HOST_WIDE_INT)X) >> (HOST_BITS_PER_WIDE_INT - 1))
+/*
+ * Conversion routines in and out of wide-int.
+ */
+
+/* Convert OP0 into a wide int of PRECISION.  If the precision is less
+   than HOST_BITS_PER_WIDE_INT, zero extend the value of the word.
+   The overflow bit are set if the number was too large to fit in the
+   mode.  */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0,
+		     unsigned int precision)
+{
+  wide_int result;
+
+  result.precision = precision;
+  result.val[0] = op0;
+  result.len = 1;
+
+  return result;
+}
+
+/* Convert OP0 into a wide int of PRECISION.  If the precision is less
+   than HOST_BITS_PER_WIDE_INT, zero extend the value of the word.
+   The overflow bit are set if the number was too large to fit in the
+   mode.  */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, 
+		     unsigned int precision)
+{
+  wide_int result;
+
+  result.precision = precision;
+  result.val[0] = op0;
+
+  /* If the top bit is a 1, we need to add another word of 0s since
+     that would not expand the right value since the infinite
+     expansion of any unsigned number must have 0s at the top.  */
+  if ((HOST_WIDE_INT)op0 < 0 && precision > HOST_BITS_PER_WIDE_INT)
+    {
+      result.val[1] = 0;
+      result.len = 2;
+    }
+  else
+    result.len = 1;
+
+  return result;
+}
+
+/* Create a wide_int from an array of host_wide_ints in OP1 of LEN.
+   The result has PRECISION.  */
+
+wide_int
+wide_int::from_array (const HOST_WIDE_INT *op1, unsigned int len, 
+		      unsigned int precision, bool need_canon)
+{
+  unsigned int i;
+  wide_int result;
+  
+  result.len = len;
+  result.precision = precision;
+
+  for (i=0; i < len; i++)
+    result.val[i] = op1[i];
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Convert a double int into a wide int with precision PREC.  */
+
+wide_int
+wide_int::from_double_int (double_int di, unsigned int prec)
+{
+  HOST_WIDE_INT op = di.low;
+  wide_int result;
+
+  result.precision = prec;
+  result.len = (prec <= HOST_BITS_PER_WIDE_INT) ? 1 : 2;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result.val[0] = sext_hwi (op, prec);
+  else
+    {
+      result.val[0] = op;
+      if (prec > HOST_BITS_PER_WIDE_INT)
+	{
+	  if (prec < HOST_BITS_PER_DOUBLE_INT)
+	    result.val[1] = sext_hwi (di.high, prec);
+	  else
+	    result.val[1] = di.high;
+	}
+    }
+
+  if (result.len == 2)
+    result.canonize ();
+
+  return result;
+}
+
+/* Convert a integer cst into a wide int.  */
+
+wide_int
+wide_int::from_tree (const_tree tcst)
+{
+  wide_int result;
+  tree type = TREE_TYPE (tcst);
+  unsigned int prec = TYPE_PRECISION (type);
+
+  result.precision = prec;
+
+  /* This will simplify out to just an array copy and a len copy.  */
+  result.val[0] = TREE_INT_CST_LOW (tcst);
+  result.val[1] = TREE_INT_CST_HIGH (tcst);
+  if (prec > HOST_BITS_PER_WIDE_INT)
+    result.len = 2;
+  else if (prec == HOST_BITS_PER_WIDE_INT
+	   && TYPE_UNSIGNED (type)
+	   && (HOST_WIDE_INT)TREE_INT_CST_LOW (tcst) < 0)
+    result.len = 2;
+  else
+    result.len = 1;
+
+  return result;
+}
+
+/* Extract a constant integer from the X of type MODE.  The bits of
+   the integer are returned.  */
+
+wide_int
+wide_int::from_rtx (const_rtx x, enum machine_mode mode)
+{
+  wide_int result;
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  gcc_assert (mode != VOIDmode);
+
+  result.precision = prec;
+
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+      result.val[0] = INTVAL (x);
+      result.len = 1;
+      break;
+
+#if TARGET_SUPPORTS_WIDE_INT
+    case CONST_WIDE_INT:
+      {
+	int i;
+	result.len = CONST_WIDE_INT_NUNITS (x);
+	
+	for (i = 0; i < result.len; i++)
+	  result.val[i] = CONST_WIDE_INT_ELT (x, i);
+      }
+      break;
+#else
+    case CONST_DOUBLE:
+      result.len = 2;
+      result.val[0] = CONST_DOUBLE_LOW (x);
+      result.val[1] = CONST_DOUBLE_HIGH (x);
+      break;
+#endif
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return result;
+}
+
+/* Construct from a buffer of length LEN.  BUFFER will be read according
+   to byte endianess and word endianess.  Only the lower LEN bytes
+   of the result are set; the remaining high bytes are cleared.  */
+
+wide_int
+wide_int::from_buffer (const unsigned char *buffer, int len)
+{
+  wide_int result = wide_int::zero (len * BITS_PER_UNIT);
+  int words = len / UNITS_PER_WORD;
+
+  for (int byte = 0; byte < len; byte++)
+    {
+      int offset;
+      int index;
+      int bitpos = byte * BITS_PER_UNIT;
+      unsigned HOST_WIDE_INT value;
+
+      if (len > UNITS_PER_WORD)
+	{
+	  int word = byte / UNITS_PER_WORD;
+
+	  if (WORDS_BIG_ENDIAN)
+	    word = (words - 1) - word;
+
+	  offset = word * UNITS_PER_WORD;
+
+	  if (BYTES_BIG_ENDIAN)
+	    offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
+	  else
+	    offset += byte % UNITS_PER_WORD;
+	}
+      else
+	offset = BYTES_BIG_ENDIAN ? (len - 1) - byte : byte;
+
+      value = (unsigned HOST_WIDE_INT) buffer[offset];
+
+      index = bitpos / HOST_BITS_PER_WIDE_INT;
+      result.val[index] |= value << bitpos;
+    }
+
+  result.canonize ();
+  return result;
+}
+
+
+/*
+ * Largest and smallest values in a mode.
+ */
+
+/* Produce the largest SGNed number that is represented in TYPE_PREC.  The
+   resulting number is placed in a wide int of size RESULT_PREC. The
+   value of 0 of RESULT_PREC says return the answer with TYPE_PREC
+   precision. */
+
+wide_int
+wide_int::max_value (unsigned int type_prec, SignOp sgn, 
+		     unsigned int result_prec)
+{
+  wide_int result;
+  
+  result.precision = result_prec ? result_prec : type_prec;
+
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned max is just all ones, for which the compressed
+	 rep is just a single HWI.  */ 
+      result.len = 1;
+      result.val[0] = (HOST_WIDE_INT)-1;
+    }
+  else
+    {
+      /* The signed max is all ones except the top bit.  This must be
+	 explicitly represented.  */
+      int i;
+      int small_prec = type_prec & (HOST_BITS_PER_WIDE_INT - 1);
+      int shift = (small_prec == 0) 
+	? HOST_BITS_PER_WIDE_INT - 1 : small_prec - 1;
+
+      result.len = BLOCKS_NEEDED (type_prec);
+      for (i = 0; i < result.len - 1; i++)
+	result.val[i] = (HOST_WIDE_INT)-1;
+
+      result.val[result.len - 1] = ((HOST_WIDE_INT)1 << shift) - 1;
+    }
+  
+  return result;
+}
+
+/* Produce the smallest SGNed number that is represented in TYPE_PREC.  The
+   resulting number is placed in a wide int of size RESULT_PREC.  */
+
+wide_int
+wide_int::min_value (unsigned int type_prec, SignOp sgn, 
+		     unsigned int result_prec)
+{
+  if (result_prec == 0)
+    result_prec = type_prec;
+
+  if (sgn == UNSIGNED)
+    {
+      /* The unsigned min is just all zeros, for which the compressed
+	 rep is just a single HWI.  */ 
+      wide_int result;
+      result.len = 1;
+      result.precision = result_prec;
+      result.val[0] = 0;
+      return result;
+    }
+  else
+    {
+      /* The signed min is all zeros except the top bit.  This must be
+	 explicitly represented.  */
+      return set_bit_in_zero (type_prec - 1, result_prec);
+    }
+}
+
+/*
+ * Public utilities.
+ */
+
+/* Check the upper HOST_WIDE_INTs of src to see if the length can be
+   shortened.  An upper HOST_WIDE_INT is unnecessary if it is all ones
+   or zeros and the top bit of the next lower word matches.
+
+   This function may change the representation of THIS, but does not
+   change the value that THIS represents.  It does not sign extend in
+   the case that the size of the mode is less than
+   HOST_BITS_PER_WIDE_INT.  */
+
+void
+wide_int::canonize ()
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT top;
+  int i;
+
+  if (len > blocks_needed)
+    len = blocks_needed;
+
+  /* Clean up the top bits for any mode that is not a multiple of a HWI.  */
+  if (len == blocks_needed && small_prec)
+    val[len - 1] = sext_hwi (val[len - 1], small_prec);
+
+  if (len == 1)
+    return;
+
+  top = val[len - 1];
+  if (top != 0 && top != (HOST_WIDE_INT)-1)
+    return;
+
+  /* At this point we know that the top is either 0 or -1.  Find the
+     first block that is not a copy of this.  */
+  for (i = len - 2; i >= 0; i--)
+    {
+      HOST_WIDE_INT x = val[i];
+      if (x != top)
+	{
+	  if (SIGN_MASK (x) == top)
+	    {
+	      len = i + 1;
+	      return;
+	    }
+
+	  /* We need an extra block because the top bit block i does
+	     not match the extension.  */
+	  len = i + 2;
+	  return;
+	}
+    }
+
+  /* The number is 0 or -1.  */
+  len = 1;
+}
+
+
+/* Make a copy of this.  */
+
+wide_int
+wide_int::copy () const
+{
+  wide_int result;
+  int i;
+
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+  return result;
+}
+
+
+/* Copy THIS replacing the precision with PREC.
+   It can do any of truncation, extension or copying.  */
+
+wide_int
+wide_int::force_to_size (unsigned int prec, SignOp sgn) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (prec);
+  int i;
+
+  result.precision = prec;
+  result.len = blocks_needed < len ? blocks_needed : len;
+  for (i = 0; i < result.len; i++)
+    result.val[i] = val[i];
+
+  if (prec >= precision) 
+    {
+      /* Expanding */
+      int small_precision = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+      /* The only case we care about is unsigned because the rep is
+	 inherantly signed.  */
+      if (sgn == UNSIGNED)
+	{
+	  /* The top block in the existing rep must be zero extended,
+	     but this is all the work we need to do.  */
+	  if (small_precision 
+	      && (len == BLOCKS_NEEDED (precision)
+		  || len == blocks_needed))
+	    result.val[len-1] = zext_hwi (result.val[len-1], small_precision);
+	  else if (len == BLOCKS_NEEDED (precision) 
+		   && len < blocks_needed
+		   && small_precision == 0
+		   && result.val[result.len - 1] < 0)
+		    /* We need to put the 0 block on top to keep the value
+		       from being sign extended.  */ 
+		    result.val[result.len++] = 0;
+	}
+    }
+  else
+    {
+      /* Truncating.  */
+      int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+      /* The only weird case we need to look at here is when we are
+         truncating within the top block.  We need to make sure that
+         everything in the block above the new precision is sign
+         extended.  Note that this is independent of the SGN.  This is
+         just to stay canonical.  */
+      if (small_prec && (blocks_needed == len))
+	result.val[blocks_needed-1]
+	  = sext_hwi (result.val[blocks_needed-1], small_prec);
+    }
+
+  return result;
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently singed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+bool
+wide_int::eq_p_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  HOST_WIDE_INT op0mask = sign_mask ();
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  while (l0 > l1)
+    if (val[l0--] != op1mask)
+      return false;
+
+  while (l1 > l0)
+    if (op1[l1--] != op0mask)
+      return false;
+
+  while (l0 >= 0)
+    if (val[l0--] != op1[l1--])
+      return false;
+
+  return true;
+}
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+bool
+wide_int::lts_p_large (const HOST_WIDE_INT *op0, unsigned int op0len, 
+		       const HOST_WIDE_INT *op1, unsigned int op1len, 
+		       unsigned int precision)
+{
+  int l;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  unsigned int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT op0mask = SIGN_MASK (op0[op0len - 1]);
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == op0len ? op0[blocks_needed - 1] : op0mask;
+  s1 = blocks_needed == op1len ? op1[blocks_needed - 1] : op1mask;
+  if (s0 < s1)
+    return true;
+  if (s0 > s1)
+    return false;
+
+  l = (signed int)MAX (op0len, op1len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == (signed int)blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < (signed int)op0len ? op0[l] : op0mask;
+      u1 = l < (signed int)op1len ? op1[l] : op1mask;
+
+      if (u0 < u1)
+	return true;
+      if (u0 > u1)
+	return false;
+      l--;
+    }
+
+  return false;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+int
+wide_int::cmps_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  int l;
+  HOST_WIDE_INT s0, s1;
+  unsigned HOST_WIDE_INT u0, u1;
+  unsigned int blocks_needed = BLOCKS_NEEDED (precision);
+  HOST_WIDE_INT op0mask = sign_mask ();
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  /* Only the top block is compared as signed.  The rest are unsigned
+     comparisons.  */
+  s0 = blocks_needed == (unsigned int)len ? val[blocks_needed - 1] : op0mask;
+  s1 = blocks_needed == op1len ? op1[blocks_needed - 1] : op1mask;
+  if (s0 < s1)
+    return -1;
+  if (s0 > s1)
+    return 1;
+
+  l = MAX (len, (signed int)op1len);
+  /* We have already checked to top block so skip down.  */
+  l = (l == (signed int)blocks_needed) ? l - 2 : l - 1;
+
+  while (l >= 0)
+    {
+      u0 = l < len ? val [l] : op0mask;
+      u1 = l < (signed int)op1len ? op1[l] : op1mask;
+
+      if (u0 < u1)
+	return -1;
+      if (u0 > u1)
+	return 1;
+      l--;
+    }
+
+  return 0;
+}
+
+/* Return true if OP0 < OP1 using unsigned comparisons.  */
+
+bool
+wide_int::ltu_p_large (const HOST_WIDE_INT *op0, unsigned int op0len, 
+		       const HOST_WIDE_INT *op1, unsigned int op1len)
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = op0len - 1;
+  int l1 = op1len - 1;
+  HOST_WIDE_INT op0mask = SIGN_MASK (op0[op0len - 1]);
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  while (l0 > l1)
+    {
+      x0 = op0[l0--];
+      x1 = op1mask;
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  while (l1 > l0)
+    {
+      x0 = op0mask;
+      x1 = op1[l1--];
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = op0[l0--];
+      x1 = op1[l1--];
+      if (x0 < x1)
+	return true;
+      if (x0 > x1)
+	return false;
+    }
+
+  return false;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+int
+wide_int::cmpu_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  HOST_WIDE_INT op0mask = sign_mask ();
+  HOST_WIDE_INT op1mask = SIGN_MASK (op1[op1len - 1]);
+
+  while (l0 > l1)
+    {
+      x0 = val[l0--];
+      x1 = op1mask;
+      if (x0 < x1)
+	return -1;
+      else if (x0 > x1)
+	return 1;
+    }
+
+  while (l1 > l0)
+    {
+      x0 = op0mask;
+      x1 = op1[l1--];
+      if (x0 < x1)
+	return -1;
+      if (x0 > x1)
+	return 1;
+    }
+
+  while (l0 >= 0)
+    {
+      x0 = val[l0--];
+      x1 = op1[l1--];
+      if (x0 < x1)
+	return -1;
+      if (x0 > x1)
+	return 1;
+    }
+
+  return 0;
+}
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p (unsigned int prec) const
+{
+  int i;
+  HOST_WIDE_INT x;
+  int small_prec;
+  bool result;
+
+  if (BLOCKS_NEEDED (prec) != len)
+    {
+      result = false;
+      goto ex;
+    }
+
+  for (i=0; i < len - 1; i++)
+    if (val[i] != 0)
+      {
+	result = false;
+	goto ex;
+      }
+
+  x = val[len - 1];
+  small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec)
+    x = x << (HOST_BITS_PER_WIDE_INT - small_prec);
+
+  result = x == ((HOST_WIDE_INT)1) << (HOST_BITS_PER_WIDE_INT - 1);
+
+ ex:
+  return result;
+}
+
+/* Returns true if THIS fits into range of TYPE.  Signedness of OP0 is
+   assumed to be the same as the signedness of TYPE.  */
+
+bool
+wide_int::fits_to_tree_p (const_tree type) const
+{
+  int type_prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return fits_u_p (type_prec);
+  else
+    return fits_s_p (type_prec);
+}
+
+/* Returns true of THIS fits in the unsigned range of precision.  */
+
+bool
+wide_int::fits_s_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == sext (prec);
+}
+
+
+/* Returns true if THIS fits into range of TYPE.  */
+
+bool
+wide_int::fits_u_p (unsigned int prec) const
+{
+  if (len < BLOCKS_NEEDED (prec))
+    return true;
+
+  if (precision <= prec)
+    return true;
+
+  return *this == zext (prec);
+}
+
+/*
+ * Extension.
+ */
+
+/* Sign extend THIS starting at OFFSET.  The precision of the result
+   are the same as THIS.  */
+
+wide_int
+wide_int::sext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = sext_hwi (val[0], offset);
+      else
+	/* If offset is greater or equal to precision there is nothing
+	   to do since the internal rep is already sign extended.  */
+	result.val[0] = val[0];
+
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, precision);
+      
+      /* Now we can do the real sign extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      if (off)
+	{
+	  int block = BLOCK_OF (offset);
+	  result.val[block] = sext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      /* We never need an extra element for sign extended values.  */
+    }    
+
+  return result;
+}
+
+/* Zero extend THIS starting at OFFSET.  The precision of the result
+   are the same as THIS.  */
+
+wide_int
+wide_int::zext (unsigned int offset) const
+{
+  wide_int result;
+  int off;
+  int block;
+
+  gcc_assert (precision >= offset);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.precision = precision;
+      if (offset < precision)
+	result.val[0] = zext_hwi (val[0], offset);
+      else if (offset == precision)
+	result.val[0] = val[0];
+	/* If offset was greater than the precision we need to zero
+	   extend from the old precision since the internal rep was
+	   equivalent to sign extended.  */
+      else
+	result.val[0] = zext_hwi (val[0], precision);
+	
+      result.len = 1;
+    }
+  else if (precision == offset)
+    result = *this;
+  else
+    {
+      result = decompress (offset, precision);
+
+      /* Now we can do the real zero extension.  */
+      off = offset & (HOST_BITS_PER_WIDE_INT - 1);
+      block = BLOCK_OF (offset);
+      if (off)
+	{
+	  result.val[block] = zext_hwi (val[block], off);
+	  result.len = block + 1;
+	}
+      else
+	/* See if we need an extra zero element to satisfy the
+	   compression rule.  */
+	if (val[block - 1] < 0 && offset < precision)
+	  {
+	    result.val[block] = 0;
+	    result.len += 1;
+	  }
+    }
+  return result;
+}
+
+/*
+ * Masking, inserting, shifting, rotating.
+ */
+
+/* Return a value with a one bit inserted in THIS at BITPOS.  */
+
+wide_int
+wide_int::set_bit (unsigned int bitpos) const
+{
+  wide_int result;
+  int i, j;
+
+  if (bitpos >= precision)
+    result = copy ();
+  else
+    {
+      result = decompress (bitpos, precision);
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+  return result;
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with PRECISION.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, unsigned int prec)
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (bitpos + 1);
+  int i, j;
+
+  result.precision = prec;
+  if (bitpos >= prec)
+    {
+      result.len = 1;
+      result.val[0] = 0;
+    }
+  else
+    {
+      result.len = blocks_needed;
+      for (i = 0; i < blocks_needed; i++)
+	result.val[i] = 0;
+      
+      j = bitpos / HOST_BITS_PER_WIDE_INT;
+      i = bitpos & (HOST_BITS_PER_WIDE_INT - 1);
+      result.val[j] |= ((HOST_WIDE_INT)1) << i;
+    }
+
+  return result;
+}
+
+/* Insert WIDTH bits from OP0 into THIS starting at START.  */
+
+wide_int
+wide_int::insert (const wide_int &op0, unsigned int start, 
+		  unsigned int width) const
+{
+  wide_int result;
+  wide_int mask;
+  wide_int tmp;
+
+  gcc_checking_assert (op0.precision >= width);
+
+  if (start + width >= precision) 
+    width = precision - start;
+
+  mask = shifted_mask (start, width, false, precision);
+  tmp = op0.lshift (start, 0, precision, NONE);
+  result = tmp & mask;
+
+  tmp = and_not (mask);
+  result = result | tmp;
+
+  return result;
+}
+
+/* bswap THIS.  */
+
+wide_int
+wide_int::bswap () const
+{
+  wide_int result;
+  int i, s;
+  int end;
+  int len = BLOCKS_NEEDED (precision);
+
+  /* This is not a well defined operation if the precision is not a
+     multiple of 8.  */
+  gcc_assert ((precision & 0x7) == 0);
+
+  result.precision = precision;
+  result.len = len;
+
+  for (i = 0; i < len; i++)
+    result.val[i] = 0;
+
+  /* Only swap the bytes that are not the padding.  */
+  if ((precision & (HOST_BITS_PER_WIDE_INT - 1))
+      && (this->len == len))
+    end = precision;
+  else
+    end = this->len * HOST_BITS_PER_WIDE_INT;
+
+  for (s = 0; s < end; s += 8)
+    {
+      unsigned int d = precision - s - 8;
+      unsigned HOST_WIDE_INT byte;
+
+      int block = s / HOST_BITS_PER_WIDE_INT;
+      int offset = s & (HOST_BITS_PER_WIDE_INT - 1);
+
+      byte = (val[block] >> offset) & 0xff;
+
+      block = d / HOST_BITS_PER_WIDE_INT;
+      offset = d & (HOST_BITS_PER_WIDE_INT - 1);
+
+      result.val[block] |= byte << offset;
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with PREC. */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  int shift;
+
+  gcc_assert (width < 2 * MAX_BITSIZE_MODE_ANY_INT);
+  gcc_assert (prec <= 2 * MAX_BITSIZE_MODE_ANY_INT);
+
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (prec);
+      else
+	result = wide_int::zero (prec);
+    }
+  else
+    {
+      result.precision = prec;
+      
+      while (i < width / HOST_BITS_PER_WIDE_INT)
+	result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+      
+      shift = width & (HOST_BITS_PER_WIDE_INT - 1);
+      if (shift != 0)
+	{
+	  HOST_WIDE_INT last = (((HOST_WIDE_INT)1) << shift) - 1;
+	  result.val[i++] = negate ? ~last : last;
+	}
+      result.len = i;
+    }
+
+  return result;
+}
+
+/* Return a result mask of WIDTH ones starting at START and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  */
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, unsigned int prec)
+{
+  wide_int result;
+  unsigned int i = 0;
+  unsigned int shift;
+  unsigned int end = start + width;
+  HOST_WIDE_INT block;
+
+  if (start + width > prec)
+    width = prec - start;
+ 
+  if (width == 0)
+    {
+      if (negate)
+	result = wide_int::minus_one (prec);
+      else
+	result = wide_int::zero (prec);
+      return result;
+    }
+
+  result.precision = prec;
+
+  while (i < start / HOST_BITS_PER_WIDE_INT)
+    result.val[i++] = negate ? (HOST_WIDE_INT)-1 : 0;
+
+  shift = start & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift)
+    {
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      shift = (end) & (HOST_BITS_PER_WIDE_INT - 1);
+      if (shift)
+	{
+	  /* case 000111000 */
+	  block = (((HOST_WIDE_INT)1) << shift) - block - 1;
+	  result.val[i++] = negate ? ~block : block;
+	  result.len = i;
+	  return result;
+	}
+      else
+	/* ...111000 */
+	result.val[i++] = negate ? block : ~block;
+    }
+
+  while (i < end / HOST_BITS_PER_WIDE_INT)
+    /* 1111111 */
+    result.val[i++] = negate ? 0 : (HOST_WIDE_INT)-1;
+
+  shift = end & (HOST_BITS_PER_WIDE_INT - 1);
+  if (shift != 0)
+    {
+      /* 000011111 */
+      block = (((HOST_WIDE_INT)1) << shift) - 1;
+      result.val[i++] = negate ? ~block : block;
+    }
+
+  result.len = i;
+  return result;
+}
+
+
+/*
+ * logical operations.
+ */
+
+/* Return THIS & OP1.  */
+
+wide_int
+wide_int::and_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (SIGN_MASK (op1[op1len - 1]) == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & op1[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Return THIS & ~OP1.  */
+
+wide_int
+wide_int::and_not_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (SIGN_MASK (op1[op1len - 1]) != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () == 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] & ~op1[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+wide_int
+wide_int::or_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (SIGN_MASK (op1[op1len - 1]) != 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = op1[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | op1[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+
+  return result;
+}
+
+/* Return THIS | ~OP1.  */
+
+wide_int
+wide_int::or_not_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+  bool need_canon = true;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  if (l0 > l1)
+    {
+      if (SIGN_MASK (op1[op1len - 1]) == 0)
+	{
+	  l0 = l1;
+	  result.len = l1 + 1;
+	}
+      else
+	{
+	  need_canon = false;
+	  while (l0 > l1)
+	    {
+	      result.val[l0] = val[l0];
+	      l0--;
+	    }
+	}
+    }
+  else if (l1 > l0)
+    {
+      if (sign_mask () != 0)
+	result.len = l0 + 1;
+      else
+	{
+	  need_canon = false;
+	  while (l1 > l0)
+	    {
+	      result.val[l1] = ~op1[l1];
+	      l1--;
+	    }
+	}
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] | ~op1[l0];
+      l0--;
+    }
+
+  if (need_canon)
+    result.canonize ();
+  return result;
+}
+
+/* Return the exclusive ior (xor) of THIS and OP1.  */
+
+wide_int
+wide_int::xor_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  int l0 = len - 1;
+  int l1 = op1len - 1;
+
+  result.len = MAX (len, op1len);
+  result.precision = precision;
+
+  while (l0 > l1)
+    {
+      result.val[l0] = val[l0] ^ SIGN_MASK (op1[op1len - 1]);
+      l0--;
+    }
+
+  while (l1 > l0)
+    {
+      result.val[l1] = sign_mask () ^ op1[l1];
+      l1--;
+    }
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = val[l0] ^ op1[l0];
+      l0--;
+    }
+
+  result.canonize ();
+  return result;
+}
+
+/*
+ * math
+ */
+
+/* Absolute value of THIS.  */
+
+wide_int
+wide_int::abs () const
+{
+  if (sign_mask ())
+    return neg ();
+
+  wide_int result = copy ();
+  return result;
+}
+
+/* Add of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::add_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  unsigned HOST_WIDE_INT carry = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.precision = precision;
+  result.len = MAX (len, op1len);
+  mask0 = sign_mask ();
+  mask1 = SIGN_MASK (op1[op1len - 1]);
+  /* Add all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1len ? (unsigned HOST_WIDE_INT)op1[i] : mask1;
+      x = o0 + o1 + carry;
+      result.val[i] = x;
+      carry = x < o0;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 + mask1 + carry;
+      result.len++;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+  return result;
+}
+
+
+/* Count leading zeros of THIS but only looking at the bits in the
+   smallest HWI of size mode.  */
+
+wide_int
+wide_int::clz () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CLZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+    }
+  else
+    {
+      /* The high order block is special if it is the last block and the
+	 precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+	 have to clear out any ones above the precision before doing clz
+	 on this block.  */
+      if (BLOCKS_NEEDED (precision) == len && small_prec)
+	{
+	  v = zext_hwi (val[len - 1], small_prec);
+	  count = clz_hwi (v) - (HOST_BITS_PER_WIDE_INT - small_prec);
+	  start = len - 2;
+	  if (v != 0)
+	    return from_shwi (count, precision);
+	}
+      else
+	{
+	  count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+	  start = len - 1;
+	}
+      
+      for (i = start; i >= 0; i--)
+	{
+	  v = elt (i);
+	  count += clz_hwi (v);
+	  if (v != 0)
+	    break;
+	}
+    }
+  return from_shwi (count, precision);
+}
+
+/* Count the number of redundant leading bits of THIS.  Return result
+   as a HOST_WIDE_INT.  */
+
+wide_int
+wide_int::clrsb () const
+{
+  if (neg_p ())
+    return operator ~ ().clz () - 1;
+
+  return clz () - 1;
+}
+
+/* Count zeros of THIS.   */
+
+wide_int
+wide_int::ctz () const
+{
+  int i;
+  unsigned int count = 0;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  int end;
+  bool more_to_do;
+
+  if (zero_p ())
+    {
+      enum machine_mode mode = mode_for_size (precision, MODE_INT, 0);
+      if (mode == BLKmode)
+	mode_for_size (precision, MODE_PARTIAL_INT, 0); 
+
+      /* Even if the value at zero is undefined, we have to come up
+	 with some replacement.  Seems good enough.  */
+      if (mode == BLKmode)
+	count = precision;
+      else if (!CTZ_DEFINED_VALUE_AT_ZERO (mode, count))
+	count = precision;
+    }
+  else
+    {
+      /* The high order block is special if it is the last block and the
+	 precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+	 have to clear out any ones above the precision before doing clz
+	 on this block.  */
+      if (BLOCKS_NEEDED (precision) == len && small_prec)
+	{
+	  end = len - 1;
+	  more_to_do = true;
+	}
+      else
+	{
+	  end = len;
+	  more_to_do = false;
+	}
+      
+      for (i = 0; i < end; i++)
+	{
+	  v = val[i];
+	  count += ctz_hwi (v);
+	  if (v != 0)
+	    return wide_int::from_shwi (count, precision);
+	}
+      
+      if (more_to_do)
+	{
+	  v = zext_hwi (val[len - 1], small_prec);
+	  count = ctz_hwi (v);
+	  /* The top word was all zeros so we have to cut it back to prec,
+	     because we are counting some of the zeros above the
+	     interesting part.  */
+	  if (count > precision)
+	    count = precision;
+	}
+      else
+	/* Skip over the blocks that are not represented.  They must be
+	   all zeros at this point.  */
+	count = precision;
+    }
+
+  return wide_int::from_shwi (count, precision);
+}
+
+/* ffs of THIS.  */
+
+wide_int
+wide_int::ffs () const
+{
+  HOST_WIDE_INT count = ctz ().to_shwi ();
+  if (count == precision)
+    count = 0;
+  else
+    count += 1;
+  return wide_int::from_shwi (count, precision);
+}
+
+/* Subroutines of the multiplication and division operations.  Unpack
+   the first IN_LEN HOST_WIDE_INTs in INPUT into 2 * IN_LEN
+   HOST_HALF_WIDE_INTs of RESULT.  The rest of RESULT is filled by
+   uncompressing the top bit of INPUT[IN_LEN - 1].  */
+
+static void
+wi_unpack (unsigned HOST_HALF_WIDE_INT *result, 
+	   const unsigned HOST_WIDE_INT *input,
+	   int in_len, int out_len)
+{
+  int i;
+  int j = 0;
+  HOST_WIDE_INT mask;
+
+  for (i = 0; i <in_len; i++)
+    {
+      result[j++] = input[i];
+      result[j++] = input[i] >> HOST_BITS_PER_HALF_WIDE_INT;
+    }
+  mask = SIGN_MASK (input[in_len - 1]);
+  mask &= HALF_INT_MASK;
+
+  /* Smear the sign bit.  */
+  while (j < out_len)
+    result[j++] = mask;
+}
+
+/* The inverse of wi_unpack.  IN_LEN is the the number of input
+   blocks.  The number of output blocks will be half this amount.  */
+
+static void
+wi_pack (unsigned HOST_WIDE_INT *result, 
+	 const unsigned HOST_HALF_WIDE_INT *input, 
+	 int in_len)
+{
+  int i = 0;
+  int j = 0;
+
+  while (i < in_len - 2)
+    {
+      result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+	| ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+      i += 2;
+    }
+
+  /* Handle the case where in_len is odd.   For this we zero extend.  */
+  if (i & 1)
+    result[j++] = (unsigned HOST_WIDE_INT)input[i];
+  else
+    result[j++] = (unsigned HOST_WIDE_INT)input[i] 
+      | ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
+}
+
+/* Return an integer that is the exact log2 of THIS.  */
+
+wide_int
+wide_int::exact_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  wide_int count;
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec)
+	v = zext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = wide_int::from_shwi (::exact_log2 (v), precision);
+    }
+  else
+    {
+      count = ctz ();
+      if (clz () + count + 1 == precision)
+	result = count;
+      else
+	result = wide_int::from_shwi (-1, precision);
+    }
+  return result;
+}
+
+/* Return an integer that is the floor log2 of THIS.  */
+
+wide_int
+wide_int::floor_log2 () const
+{
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  wide_int result;
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      HOST_WIDE_INT v;
+      if (small_prec)
+	v = zext_hwi (val[0], small_prec);
+      else
+	v = val[0];
+      result = wide_int::from_shwi (::floor_log2 (v), precision);
+    }
+  else
+    result = wide_int::from_shwi (precision, precision) - 1 - clz ();
+  return result;
+}
+
+
+/* Multiply Op1 by Op2.  If HIGH is set, only the upper half of the
+   result is returned.  If FULL is set, the entire result is returned
+   in a mode that is twice the width of the inputs.  However, that
+   mode needs to exist if the value is to be usable.  Clients that use
+   FULL need to check for this.
+
+   If HIGH or FULL are not setm throw away the upper half after the check
+   is made to see if it overflows.  Unfortunately there is no better
+   way to check for overflow than to do this.  OVERFLOW is assumed to
+   be sticky so it should be initialized.  SGN controls the signess
+   and is used to check overflow or if HIGH or FULL is set.  */
+
+wide_int
+wide_int::mul_internal (bool high, bool full, 
+			const wide_int *op1, 
+			const HOST_WIDE_INT *op2, unsigned int op2len,
+			SignOp sgn,  bool *overflow, 
+			bool needs_overflow)
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1, k, t;
+  unsigned int i;
+  unsigned int j;
+  unsigned int prec = op1->get_precision ();
+  unsigned int blocks_needed = BLOCKS_NEEDED (prec);
+  unsigned int half_blocks_needed = blocks_needed * 2;
+  /* The sizes here are scaled to support a 2x largest mode by 2x
+     largest mode yielding a 4x largest mode result.  This is what is
+     needed by vpn.  */
+
+  unsigned HOST_HALF_WIDE_INT 
+    u[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT 
+    v[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  /* The '2' in 'R' is because we are internally doing a full
+     multiply.  */
+  unsigned HOST_HALF_WIDE_INT 
+    r[2 * 2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT) - 1;
+
+  /* If the top level routine did not really pass in an overflow, then
+     just make sure that we never attempt to set it.  */
+  if (overflow == 0)
+    needs_overflow = false;
+  result.precision = op1->precision;
+
+  if (high || full || needs_overflow)
+    {
+      /* If we need to check for overflow, we can only do half wide
+	 multiplies quickly because we need to look at the top bits to
+	 check for the overflow.  */
+      if (prec <= HOST_BITS_PER_HALF_WIDE_INT)
+	{
+	  HOST_WIDE_INT t, r;
+	  result.len = 1;
+	  o0 = op1->elt (0);
+	  o1 = op2[0];
+	  r = o0 * o1;
+	  /* Signed shift down will leave 0 or -1 if there was no
+	     overflow for signed or 0 for unsigned.  */
+	  t = SIGN_MASK (r);
+	  if (needs_overflow)
+	    {
+	      if (sgn == SIGNED)
+		{
+		  if (t != (HOST_WIDE_INT)-1 && t != 0)
+		    *overflow = true;
+		}
+	      else
+		{
+		  if (t != 0)
+		    *overflow = true;
+		}
+	    }
+	  if (full)
+	    {
+	      result.val[0] = sext_hwi (r, prec * 2);
+	      result.precision = op1->precision * 2;
+	    }
+	  else if (high)
+	    result.val[0] = r >> prec;
+	  else
+	    result.val[0] = sext_hwi (r, prec);
+	  return result;
+	}
+    }
+
+  wi_unpack (u, (const unsigned HOST_WIDE_INT*)op1->val, op1->len,
+	     half_blocks_needed);
+  wi_unpack (v, (const unsigned HOST_WIDE_INT*)op2, op2len,
+	     half_blocks_needed);
+
+  /* The 2 is for a full mult.  */
+  memset (r, 0, half_blocks_needed * 2 
+	  * HOST_BITS_PER_HALF_WIDE_INT / BITS_PER_UNIT);
+
+  for (j = 0; j < half_blocks_needed; j++)
+    {
+      k = 0;
+      for (i = 0; i < half_blocks_needed; i++)
+	{
+	  t = ((unsigned HOST_WIDE_INT)u[i] * (unsigned HOST_WIDE_INT)v[j]
+	       + r[i + j] + k);
+	  r[i + j] = t & HALF_INT_MASK;
+	  k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	}
+      r[j + half_blocks_needed] = k;
+    }
+
+  /* We did unsigned math above.  For signed we must adjust the
+     product (assuming we need to see that).  */
+  if (sgn == SIGNED && (full || high || needs_overflow))
+    {
+      unsigned HOST_WIDE_INT b;
+      if ((*op1).neg_p ())
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)v[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+      if (op2[op2len-1] < 0)
+	{
+	  b = 0;
+	  for (i = 0; i < half_blocks_needed; i++)
+	    {
+	      t = (unsigned HOST_WIDE_INT)r[i + half_blocks_needed]
+		- (unsigned HOST_WIDE_INT)u[i] - b;
+	      r[i + half_blocks_needed] = t & HALF_INT_MASK;
+	      b = t >> (HOST_BITS_PER_WIDE_INT - 1);
+	    }
+	}
+    }
+
+  if (needs_overflow)
+    {
+      HOST_WIDE_INT top;
+
+      /* For unsigned, overflow is true if any of the top bits are set.
+	 For signed, overflow is true if any of the top bits are not equal
+	 to the sign bit.  */
+      if (sgn == UNSIGNED)
+	top = 0;
+      else
+	{
+	  top = r[(half_blocks_needed) - 1];
+	  top = SIGN_MASK (top << (HOST_BITS_PER_WIDE_INT / 2));
+	  top &= mask;
+	}
+      
+      for (i = half_blocks_needed; i < half_blocks_needed * 2; i++)
+	if (((HOST_WIDE_INT)(r[i] & mask)) != top)
+	  *overflow = true; 
+    }
+
+  if (full)
+    {
+      /* compute [2prec] <- [prec] * [prec] */
+      wi_pack ((unsigned HOST_WIDE_INT*)result.val, r, 2 * half_blocks_needed);
+      result.len = blocks_needed * 2;
+      result.precision = op1->precision * 2;
+    }
+  else if (high)
+    {
+      /* compute [prec] <- ([prec] * [prec]) >> [prec] */
+      wi_pack ((unsigned HOST_WIDE_INT*)&result.val [blocks_needed >> 1],
+	       r, half_blocks_needed);
+      result.len = blocks_needed;
+    }
+  else
+    {
+      /* compute [prec] <- ([prec] * [prec]) && ((1 << [prec]) - 1) */
+      wi_pack ((unsigned HOST_WIDE_INT*)result.val, r, half_blocks_needed);
+      result.len = blocks_needed;
+    }
+      
+  result.canonize ();
+  return result;
+}
+
+/* Compute the parity of THIS.  */
+
+wide_int
+wide_int::parity () const
+{
+  wide_int count = popcount ();
+  return count & 1;
+}
+
+/* Compute the population count of THIS.  */
+
+wide_int
+wide_int::popcount () const
+{
+  int i;
+  int start;
+  int count;
+  HOST_WIDE_INT v;
+  int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+
+  /* The high order block is special if it is the last block and the
+     precision is not an even multiple of HOST_BITS_PER_WIDE_INT.  We
+     have to clear out any ones above the precision before doing clz
+     on this block.  */
+  if (BLOCKS_NEEDED (precision) == len && small_prec)
+    {
+      v = zext_hwi (val[len - 1], small_prec);
+      count = popcount_hwi (v);
+      start = len - 2;
+    }
+  else
+    {
+      if (sign_mask ())
+	count = HOST_BITS_PER_WIDE_INT * (BLOCKS_NEEDED (precision) - len);
+      else
+	count = 0;
+      start = len - 1;
+    }
+
+  for (i = start; i >= 0; i--)
+    {
+      v = val[i];
+      count += popcount_hwi (v);
+    }
+  return wide_int::from_shwi (count, precision);
+}
+
+/* Subtract of THIS and OP1.  No overflow is detected.  */
+
+wide_int
+wide_int::sub_large (const HOST_WIDE_INT *op1, unsigned int op1len) const
+{
+  wide_int result;
+  unsigned HOST_WIDE_INT o0, o1;
+  unsigned HOST_WIDE_INT x = 0;
+  /* We implement subtraction as an in place negate and add.  Negation
+     is just inversion and add 1, so we can do the add of 1 by just
+     starting the borrow in of the first element at 1.  */
+  unsigned HOST_WIDE_INT borrow = 0;
+  unsigned HOST_WIDE_INT mask0, mask1;
+  unsigned int i, small_prec;
+
+  result.precision = precision;
+  result.len = MAX (len, op1len);
+  mask0 = sign_mask ();
+  mask1 = SIGN_MASK (op1[op1len - 1]);
+
+  /* Subtract all of the explicitly defined elements.  */
+  for (i = 0; i < result.len; i++)
+    {
+      o0 = i < len ? (unsigned HOST_WIDE_INT)val[i] : mask0;
+      o1 = i < op1len ? (unsigned HOST_WIDE_INT)op1[i] : mask1;
+      x = o0 - o1 - borrow;
+      result.val[i] = x;
+      borrow = o0 < o1;
+    }
+
+  if (len * HOST_BITS_PER_WIDE_INT < precision)
+    {
+      result.val[result.len] = mask0 - mask1 - borrow;
+      result.len++;
+    }
+
+  small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+  if (small_prec != 0 && BLOCKS_NEEDED (precision) == result.len)
+    {
+      /* Modes with weird precisions.  */
+      i = result.len - 1;
+      result.val[i] = sext_hwi (result.val[i], small_prec);
+    }
+
+  result.canonize ();
+  return result;
+}
+
+
+/*
+ * Division and Mod
+ */
+
+/* Compute B_QUOTIENT and B_REMAINDER from B_DIVIDEND/B_DIVISOR.  The
+   algorithm is a small modification of the algorithm in Hacker's
+   Delight by Warren, which itself is a small modification of Knuth's
+   algorithm.  M is the number of significant elements of U however
+   there needs to be at least one extra element of B_DIVIDEND
+   allocated, N is the number of elements of B_DIVISOR.  */
+
+void
+wide_int::divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+			     unsigned HOST_HALF_WIDE_INT *b_remainder,
+			     unsigned HOST_HALF_WIDE_INT *b_dividend, 
+			     unsigned HOST_HALF_WIDE_INT *b_divisor, 
+			     int m, int n)
+{
+  /* The "digits" are a HOST_HALF_WIDE_INT which the size of half of a
+     HOST_WIDE_INT and stored in the lower bits of each word.  This
+     algorithm should work properly on both 32 and 64 bit
+     machines.  */
+  unsigned HOST_WIDE_INT b
+    = (unsigned HOST_WIDE_INT)1 << HOST_BITS_PER_HALF_WIDE_INT;
+  unsigned HOST_WIDE_INT qhat;   /* Estimate of quotient digit.  */
+  unsigned HOST_WIDE_INT rhat;   /* A remainder.  */
+  unsigned HOST_WIDE_INT p;      /* Product of two digits.  */
+  HOST_WIDE_INT s, i, j, t, k;
+
+  /* Single digit divisor.  */
+  if (n == 1)
+    {
+      k = 0;
+      for (j = m - 1; j >= 0; j--)
+	{
+	  b_quotient[j] = (k * b + b_dividend[j])/b_divisor[0];
+	  k = ((k * b + b_dividend[j])
+	       - ((unsigned HOST_WIDE_INT)b_quotient[j]
+		  * (unsigned HOST_WIDE_INT)b_divisor[0]));
+	}
+      b_remainder[0] = k;
+      return;
+    }
+
+  s = clz_hwi (b_divisor[n-1]) - HOST_BITS_PER_HALF_WIDE_INT; /* CHECK clz */
+
+  /* Normalize B_DIVIDEND and B_DIVISOR.  Unlike the published
+     algorithm, we can overwrite b_dividend and b_divisor, so we do
+     that.  */
+  for (i = n - 1; i > 0; i--)
+    b_divisor[i] = (b_divisor[i] << s)
+      | (b_divisor[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_divisor[0] = b_divisor[0] << s;
+
+  b_dividend[m] = b_dividend[m-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s);
+  for (i = m - 1; i > 0; i--)
+    b_dividend[i] = (b_dividend[i] << s)
+      | (b_dividend[i-1] >> (HOST_BITS_PER_HALF_WIDE_INT - s));
+  b_dividend[0] = b_dividend[0] << s;
+
+  /* Main loop.  */
+  for (j = m - n; j >= 0; j--)
+    {
+      qhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) / b_divisor[n-1];
+      rhat = (b_dividend[j+n] * b + b_dividend[j+n-1]) - qhat * b_divisor[n-1];
+    again:
+      if (qhat >= b || qhat * b_divisor[n-2] > b * rhat + b_dividend[j+n-2])
+	{
+	  qhat -= 1;
+	  rhat += b_divisor[n-1];
+	  if (rhat < b)
+	    goto again;
+	}
+
+      /* Multiply and subtract.  */
+      k = 0;
+      for (i = 0; i < n; i++)
+	{
+	  p = qhat * b_divisor[i];
+	  t = b_dividend[i+j] - k - (p & HALF_INT_MASK);
+	  b_dividend[i + j] = t;
+	  k = ((p >> HOST_BITS_PER_HALF_WIDE_INT)
+	       - (t >> HOST_BITS_PER_HALF_WIDE_INT));
+	}
+      t = b_dividend[j+n] - k;
+      b_dividend[j+n] = t;
+
+      b_quotient[j] = qhat;
+      if (t < 0)
+	{
+	  b_quotient[j] -= 1;
+	  k = 0;
+	  for (i = 0; i < n; i++)
+	    {
+	      t = (HOST_WIDE_INT)b_dividend[i+j] + b_divisor[i] + k;
+	      b_dividend[i+j] = t;
+	      k = t >> HOST_BITS_PER_HALF_WIDE_INT;
+	    }
+	  b_dividend[j+n] += k;
+	}
+    }
+  for (i = 0; i < n; i++)
+    b_remainder[i] = (b_dividend[i] >> s) 
+      | (b_dividend[i+1] << (HOST_BITS_PER_HALF_WIDE_INT - s));
+}
+
+
+/* Do a truncating divide DIVISOR into DIVIDEND.  The result is the
+   same size as the operands.  SIGN is either wide_int::SIGNED or
+   wide_int::UNSIGNED.  */
+
+wide_int
+wide_int::divmod_internal (bool compute_quotient, 
+			   const wide_int *dividend, 
+			   const HOST_WIDE_INT *divisor,
+			   unsigned int divisorlen,
+			   SignOp sgn, wide_int *remainder,
+			   bool compute_remainder, 
+			   bool *oflow)
+{
+  wide_int quotient, u0, u1;
+  unsigned int prec = dividend->get_precision();
+  int blocks_needed = 2 * BLOCKS_NEEDED (prec);
+  /* The '2' in the next 4 vars are because they are built on half
+     sized wide ints.  */
+  unsigned HOST_HALF_WIDE_INT 
+    b_quotient[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_remainder[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  unsigned HOST_HALF_WIDE_INT
+    b_dividend[(MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT) + 1];
+  unsigned HOST_HALF_WIDE_INT
+    b_divisor[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_HALF_WIDE_INT];
+  int m, n;
+  bool dividend_neg = false;
+  bool divisor_neg = false;
+  bool overflow = false;
+
+  if (divisor[0] == 0 && divisorlen == 1)
+    overflow = true;
+
+  /* The smallest signed number / -1 causes overflow.  */
+  if (sgn == SIGNED)
+    {
+      wide_int t = wide_int::set_bit_in_zero (prec - 1, prec);
+      if (*dividend == t && divisor[0] == -1 && divisorlen == 1)
+	overflow = true;
+    }
+
+  quotient.precision = prec;
+  remainder->precision = prec;
+
+  /* If overflow is set, just get out.  There will only be grief by
+     continuing.  */
+  if (overflow)
+    {
+      if (compute_remainder)
+	{
+	  remainder->len = 1;
+	  remainder->val[0] = 0;
+	}
+      if (oflow != 0)
+	*oflow = true;
+      return wide_int::zero (prec);
+    }
+
+  /* Do it on the host if you can.  */
+  if (prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      quotient.len = 1;
+      remainder->len = 1;
+      if (sgn == SIGNED)
+	{
+	  quotient.val[0] 
+	    = sext_hwi (dividend->val[0] / divisor[0], prec);
+	  remainder->val[0] 
+	    = sext_hwi (dividend->val[0] % divisor[0], prec);
+	}
+      else
+	{
+	  unsigned HOST_WIDE_INT o0 = dividend->val[0];
+	  unsigned HOST_WIDE_INT o1 = divisor[0];
+
+	  if (prec < HOST_BITS_PER_WIDE_INT)
+	    {
+	      o0 = zext_hwi (o0, prec);
+	      o1 = zext_hwi (o1, prec);
+	    }
+	  quotient.val[0] = sext_hwi (o0 / o1, prec);
+	  remainder->val[0] = sext_hwi (o0 % o1, prec);
+	}
+      return quotient;
+    }
+
+  /* Make the divisor and divident positive and remember what we
+     did.  */
+  if (sgn == SIGNED)
+    {
+      if (dividend->sign_mask ())
+	{
+	  u0 = dividend->neg ();
+	  dividend = &u0;
+	  dividend_neg = true;
+	}
+      if (divisor[divisorlen - 1] < 0)
+	{
+	  u1 = wide_int::zero (dividend->precision).sub_large (divisor, divisorlen);
+	  divisor = u1.val;
+	  divisorlen = u1.len;
+	  divisor_neg = true;
+	}
+    }
+
+  wi_unpack (b_dividend, (const unsigned HOST_WIDE_INT*)dividend->val,
+	     dividend->len, blocks_needed);
+  wi_unpack (b_divisor, (const unsigned HOST_WIDE_INT*)divisor, 
+	     divisorlen, blocks_needed);
+
+  if (dividend->sign_mask ())
+    m = blocks_needed;
+  else
+    m = 2 * dividend->get_len ();
+
+  if (SIGN_MASK (divisor[divisorlen - 1]))
+    n = blocks_needed;
+  else
+    n = 2 * divisorlen;
+
+  /* It is known that the top input block to the divisor is non zero,
+     but when this block is split into two half blocks, it may be that
+     the top half block is zero.  Skip over this half block.  */
+  if (b_divisor[n - 1] == 0)
+    n--;
+
+  divmod_internal_2 (b_quotient, b_remainder, b_dividend, b_divisor, m, n);
+
+  if (compute_quotient)
+    {
+      wi_pack ((unsigned HOST_WIDE_INT*)quotient.val, b_quotient, m);
+      quotient.len = m / 2;
+      quotient.canonize ();
+      /* The quotient is neg if exactly one of the divisor or dividend is
+	 neg.  */
+      if (dividend_neg != divisor_neg)
+	quotient = quotient.neg ();
+    }
+  else
+    quotient = wide_int::zero (dividend->precision);
+
+  if (compute_remainder)
+    {
+      wi_pack ((unsigned HOST_WIDE_INT*)remainder->val, b_remainder, n);
+      if (n & 1)
+	n++;
+      remainder->len = n / 2;
+      (*remainder).canonize ();
+      /* The remainder is always the same sign as the dividend.  */
+      if (dividend_neg)
+	*remainder = (*remainder).neg ();
+    }
+  else
+    *remainder = wide_int::zero (dividend->precision);
+  return quotient;
+}
+
+
+/*
+ * Shifting, rotating and extraction.
+ */
+
+/* Extract WIDTH bits from THIS starting at OFFSET.  The result is
+   assumed to fit in a HOST_WIDE_INT.  This function is safe in that
+   it can properly access elements that may not be explicitly
+   represented.  */
+
+HOST_WIDE_INT
+wide_int::extract_to_hwi (int offset, int width) const
+{
+  int start_elt, end_elt, shift;
+  HOST_WIDE_INT x;
+
+  /* Get rid of the easy cases first.   */
+  if (offset >= len * HOST_BITS_PER_WIDE_INT)
+    return sign_mask ();
+  if (offset + width <= 0)
+    return 0;
+
+  shift = offset & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset < 0)
+    {
+      start_elt = -1;
+      end_elt = 0;
+      x = 0;
+    }
+  else
+    {
+      start_elt = offset / HOST_BITS_PER_WIDE_INT;
+      end_elt = (offset + width - 1) / HOST_BITS_PER_WIDE_INT;
+      x = start_elt >= len 
+	? sign_mask ()
+	: (unsigned HOST_WIDE_INT)val[start_elt] >> shift;
+    }
+
+  if (start_elt != end_elt)
+    {
+      HOST_WIDE_INT y = end_elt == len
+	? sign_mask () : val[end_elt];
+
+      x |= y << (HOST_BITS_PER_WIDE_INT - shift);
+    }
+
+  if (width != HOST_BITS_PER_WIDE_INT)
+    x &= ((HOST_WIDE_INT)1 << width) - 1;
+
+  return x;
+}
+
+
+/* Left shift THIS by CNT.  See the definition of Op.TRUNC for how to
+   set Z.  Since this is used internally, it has the ability to
+   specify the BISIZE and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+wide_int
+wide_int::lshift_large (unsigned int cnt, unsigned int res_prec) const
+{
+  wide_int result;
+  unsigned int i;
+
+  result.precision = res_prec;
+
+  if (cnt >= res_prec)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+      return result;
+    }
+
+  for (i = 0; i < res_prec; i += HOST_BITS_PER_WIDE_INT)
+    result.val[i / HOST_BITS_PER_WIDE_INT]
+      = extract_to_hwi (i - cnt, HOST_BITS_PER_WIDE_INT);
+
+  result.len = BLOCKS_NEEDED (res_prec);
+  result.canonize ();
+
+  return result;
+}
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set Z.  */
+
+wide_int
+wide_int::rshiftu_large (unsigned int cnt) const
+{
+  wide_int result;
+  int stop_block, offset, i;
+
+  result.precision = precision;
+
+  if (cnt >= precision)
+    {
+      result.val[0] = 0;
+      result.len = 1;
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  offset = (precision - cnt) & (HOST_BITS_PER_WIDE_INT - 1);
+  if (offset)
+    result.val[stop_block - 1] = zext_hwi (result.val[stop_block - 1], offset);
+  else
+    /* The top block had a 1 at the top position so it will decompress
+       wrong unless a zero block is added.  This only works because we
+       know the shift was greater than 0.  */
+    if (result.val[stop_block - 1] < 0)
+      result.val[result.len++] = 0;
+  return result;
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set Z.  */
+
+wide_int
+wide_int::rshifts_large (unsigned int cnt) const
+{
+  wide_int result;
+  int stop_block, i;
+
+  result.precision = precision;
+
+  if (cnt >= precision)
+    {
+      HOST_WIDE_INT m = sign_mask ();
+      result.val[0] = m;
+      result.len = 1;
+      return result;
+    }
+
+  stop_block = BLOCKS_NEEDED (precision - cnt);
+  for (i = 0; i < stop_block; i++)
+    result.val[i]
+      = extract_to_hwi ((i * HOST_BITS_PER_WIDE_INT) + cnt,
+			HOST_BITS_PER_WIDE_INT);
+
+  result.len = stop_block;
+
+  /* No need to sign extend the last block, since it extract_to_hwi
+     already did that.  */
+  return result;
+}
+
+/*
+ * Private utilities.
+ */
+/* Decompress THIS for at least TARGET bits into a result with
+   precision PREC.  */
+
+wide_int
+wide_int::decompress (unsigned int target, unsigned int prec) const
+{
+  wide_int result;
+  int blocks_needed = BLOCKS_NEEDED (target);
+  HOST_WIDE_INT mask;
+  int len, i;
+
+  result.precision = prec;
+  result.len = blocks_needed;
+
+  for (i = 0; i < this->len; i++)
+    result.val[i] = val[i];
+
+  len = this->len;
+
+  if (target > result.precision)
+    return result;
+
+  /* The extension that we are doing here is not sign extension, it is
+     decompression.  */
+  mask = sign_mask ();
+  while (len < blocks_needed)
+    result.val[len++] = mask;
+
+  return result;
+}
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
new file mode 100644
index 0000000..ed9f831
--- /dev/null
+++ b/gcc/wide-int.h
@@ -0,0 +1,2411 @@
+/* Operations with very long integers.  -*- C++ -*-
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3, or (at your option) any
+later version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef WIDE_INT_H
+#define WIDE_INT_H
+
+/* Wide-int.[ch] implements a class that efficiently performs
+   mathematical operations on finite precision integers.  Wide-ints
+   are designed to be transient - they are not for long term storage
+   of values.  There is tight integration between wide-ints and the
+   other longer storage GCC representations (rtl and tree).
+
+   A wide integer is represented as a vector of HOST_WIDE_INTs.  The
+   vector contains enough elements to hold a value of
+   MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT which is a
+   derived for each host/target combination.  The values are stored in
+   the vector with the least signicant HOST_BITS_PER_WIDE_INT bits of
+   the value stored in element 0.  
+
+   A wide_int contains three fields: the vector (VAL), precision and a
+   length, (LEN).  The length is the number of HWIs needed to
+   represent the value.
+
+   Wide-ints are write-once.
+
+   Since most integers used in a compiler are small values, it is
+   generally profitable to use a representation of the value that is
+   as small as possible.  LEN is used to indicate the number of
+   elements of the vector that are in use.  The numbers are stored as
+   sign entended numbers as a means of compression.  Leading
+   HOST_WIDE_INTs that contain strings of either -1 or 0 are removed
+   as long as they can be reconstructed from the top bit that is being
+   represented.
+
+   The representation does not contain any information inherant about
+   signedness of the represented value, so it can be used to represent
+   both signed and unsigned numbers.   For operations where the results
+   depend on signedness (division, comparisons), the signedness must
+   be specified separately.
+
+   Note that the bits above the precision are not defined and the
+   algorithms used here are careful not to depend on their value.  In
+   particular, values that come in from rtx constants may have random
+   bits.  */
+
+
+#ifndef GENERATOR_FILE
+#include <utility>
+#include "tree.h"
+#include "system.h"
+#include "hwint.h"
+#include "options.h"
+#include "tm.h"
+#include "insn-modes.h"
+#include "machmode.h"
+#include "double-int.h"
+#include <gmp.h>
+#include "dumpfile.h"
+#include "real.h"
+
+#define WIDE_INT_MAX_ELTS \
+  ((4 * MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+
+enum ShiftOp {
+  NONE,
+  /* There are two uses for the wide-int shifting functions.  The
+     first use is as an emulation of the target hardware.  The
+     second use is as service routines for other optimizations.  The
+     first case needs to be identified by passing TRUNC as the value
+     of ShiftOp so that shift amount is properly handled according to the
+     SHIFT_COUNT_TRUNCATED flag.  For the second case, the shift
+     amount is always truncated by the bytesize of the mode of
+     THIS.  */
+  TRUNC
+};
+
+enum SignOp {
+  /* Many of the math functions produce different results depending
+     on if they are SIGNED or UNSIGNED.  In general, there are two
+     different functions, whose names are prefixed with an 'S" and
+     or an 'U'.  However, for some math functions there is also a
+     routine that does not have the prefix and takes an SignOp
+     parameter of SIGNED or UNSIGNED.  */
+  SIGNED,
+  UNSIGNED
+};
+
+static const int DUMP_MAX = (2 * (MAX_BITSIZE_MODE_ANY_INT / 4
+				  + MAX_BITSIZE_MODE_ANY_INT 
+				  / HOST_BITS_PER_WIDE_INT + 32));
+
+class GTY(()) wide_int {
+  /* Internal representation.  */
+  
+  /* VAL is set to a size that is capable of computing a full
+     multiplication on the largest mode that is represented on the
+     target.  The full multiplication is use by tree-vrp.  tree-vpn
+     currently does a 2x largest mode by 2x largest mode yielding a 4x
+     largest mode result.  If operations are added that require larger
+     buffers, then VAL needs to be changed.  */
+  HOST_WIDE_INT val[WIDE_INT_MAX_ELTS];
+  unsigned short len;
+  unsigned int precision;
+
+ public:
+  /* Conversions.  */
+
+  static wide_int from_shwi (HOST_WIDE_INT op0, 
+			     unsigned int precision);
+  static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+			     unsigned int precision);
+
+  inline static wide_int from_hwi (HOST_WIDE_INT op0, const_tree type);
+  inline static wide_int from_shwi (HOST_WIDE_INT op0, enum machine_mode mode);
+  inline static wide_int from_uhwi (unsigned HOST_WIDE_INT op0, 
+				    enum machine_mode mode);
+  static wide_int from_array (const HOST_WIDE_INT* op0,
+			      unsigned int len, 
+			      unsigned int precision, bool need_canon = true); 
+
+  static wide_int from_double_int (double_int, 
+				   unsigned int precision);
+  static wide_int from_tree (const_tree);
+  static wide_int from_rtx (const_rtx, enum machine_mode);
+  static wide_int from_buffer (const unsigned char*, int);
+
+  inline HOST_WIDE_INT to_shwi (unsigned int prec = 0) const;
+  inline unsigned HOST_WIDE_INT to_uhwi (unsigned int prec = 0) const;
+
+  /* Largest and smallest values that are represented in a TYPE_PREC.
+     RESULT_PREC is the precision of the value that the answer is
+     returned within.  The default value of 0 says return the answer
+     with TYPE_PREC precision.  */
+  static wide_int max_value (unsigned int type_prec, 
+			     SignOp sgn, unsigned int result_prec = 0);
+  inline static wide_int max_value (const_tree type);
+  inline static wide_int max_value (enum machine_mode mode, SignOp sgn);
+  
+  static wide_int min_value (unsigned int type_prec, 
+			     SignOp sgn, unsigned int result_prec = 0);
+  inline static wide_int min_value (unsigned int precision, SignOp sgn);
+  inline static wide_int min_value (const_tree type);
+  inline static wide_int min_value (enum machine_mode mode, SignOp sgn);
+  
+  /* Small constants */
+
+  inline static wide_int minus_one (unsigned int prec);
+  inline static wide_int zero (unsigned int prec);
+  inline static wide_int one (unsigned int prec);
+  inline static wide_int two (unsigned int prec);
+
+  /* Accessors.  */
+
+  inline unsigned short get_len () const;
+  inline unsigned int get_precision () const;
+  inline HOST_WIDE_INT elt (unsigned int i) const;
+
+  /* Comparative functions.  */
+
+  inline bool minus_one_p () const;
+  inline bool zero_p () const;
+  inline bool one_p () const;
+  inline bool neg_p () const;
+
+  template <typename T>
+  inline bool operator == (const T &c) const;
+  
+  template <typename T>
+  inline bool operator != (const T &c) const;
+  
+  template <typename T>
+  inline bool gt_p (const T &c, SignOp sgn) const;
+  template <typename T>
+  inline bool gts_p (const T &c) const;
+  template <typename T>
+  inline bool gtu_p (const T &c) const;
+  
+  template <typename T>
+  inline bool lt_p (const T &c, SignOp sgn) const;
+  template <typename T>
+  inline bool lts_p (const T &c) const;
+  template <typename T>
+  inline bool ltu_p (const T &c) const;
+  
+  template <typename T>
+  inline int cmp (const T &c, SignOp sgn) const;
+  template <typename T>
+  inline int cmps (const T &c) const;
+  template <typename T>
+  inline int cmpu (const T &c) const;
+  
+  bool only_sign_bit_p (unsigned int prec) const;
+  inline bool only_sign_bit_p () const;
+  inline bool fits_uhwi_p () const;
+  inline bool fits_shwi_p () const;
+  bool fits_to_tree_p (const_tree type) const;
+  bool fits_u_p (unsigned int prec) const;
+  bool fits_s_p (unsigned int prec) const;
+
+  /* Min and max */
+
+  template <typename T>
+  inline wide_int min (const T &c, SignOp sgn) const;
+  inline wide_int min (const wide_int &op1, SignOp sgn) const;
+  template <typename T>
+  inline wide_int max (const T &c, SignOp sgn) const;
+  inline wide_int max (const wide_int &op1, SignOp sgn) const;
+  template <typename T>
+  inline wide_int smin (const T &c) const;
+  inline wide_int smin (const wide_int &op1) const;
+  template <typename T>
+  inline wide_int smax (const T &c) const;
+  inline wide_int smax (const wide_int &op1) const;
+  template <typename T>
+  inline wide_int umin (const T &c) const;
+  inline wide_int umin (const wide_int &op1) const;
+  template <typename T>
+  inline wide_int umax (const T &c) const;
+  inline wide_int umax (const wide_int &op1) const;
+
+  /* Extension, these do not change the precision.  */
+
+  inline wide_int ext (unsigned int offset, SignOp sgn) const;
+  wide_int sext (unsigned int offset) const;
+  wide_int zext (unsigned int offset) const;
+
+  /* Make a fast copy.  */
+
+  wide_int copy () const;
+
+  /* These change the underlying precision.  */
+  
+  wide_int force_to_size (unsigned int precision, SignOp sgn) const;
+  inline wide_int sforce_to_size (unsigned int precision) const;
+  inline wide_int zforce_to_size (unsigned int precision) const;
+
+  /* Masking, and Insertion  */
+
+  wide_int set_bit (unsigned int bitpos) const;
+  static wide_int set_bit_in_zero (unsigned int bitpos, unsigned int prec);
+  inline static wide_int set_bit_in_zero (unsigned int, 
+					  enum machine_mode mode);
+  inline static wide_int set_bit_in_zero (unsigned int, const_tree type);
+  wide_int insert (const wide_int &op0, unsigned int offset,
+		   unsigned int width) const;
+
+  wide_int bswap () const;
+
+  static wide_int mask (unsigned int start, bool negate, 
+			unsigned int prec);
+  inline static wide_int mask (unsigned int start, bool negate, 
+			       enum machine_mode mode);
+  inline static wide_int mask (unsigned int start, bool negate,
+			       const_tree type);
+
+  static wide_int shifted_mask (unsigned int start, unsigned int width,
+				bool negate, unsigned int prec);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, enum machine_mode mode);
+  inline static wide_int shifted_mask (unsigned int start, unsigned int width, 
+				       bool negate, const_tree type);
+
+  inline HOST_WIDE_INT sign_mask () const;
+
+  /* Logicals */
+
+  template <typename T>
+  inline wide_int operator & (const T &c) const;
+  template <typename T>
+  inline wide_int and_not (const T &c) const;
+  inline wide_int operator ~ () const;
+  template <typename T>
+  inline wide_int operator | (const T &c) const;
+  template <typename T>
+  inline wide_int or_not (const T &c) const;
+  template <typename T>
+  inline wide_int operator ^ (const T &c) const;
+  
+  /* Arithmetic operation functions, alpha sorted.  */
+  
+  wide_int abs () const;
+  template <typename T>
+  inline wide_int operator + (const T &c) const;
+  
+  wide_int clz () const;
+  wide_int clrsb () const;
+  wide_int ctz () const;
+  wide_int exact_log2 () const;
+  wide_int floor_log2 () const;
+  wide_int ffs () const;
+  
+  template <typename T>
+  inline wide_int operator * (const T &c) const;
+  template <typename T>
+  inline wide_int mul (const T &c, SignOp sgn, bool *overflow) const;
+  template <typename T>
+  inline wide_int smul (const T &c, bool *overflow) const;
+  template <typename T>
+  inline wide_int umul (const T &c, bool *overflow) const;
+  template <typename T>
+  inline wide_int mul_full (const T &c, SignOp sgn) const;
+  template <typename T>
+  inline wide_int smul_full (const T &c) const;
+  template <typename T>
+  inline wide_int umul_full (const T &c) const;
+  template <typename T>
+  inline wide_int mul_high (const T &c, SignOp sgn) const;
+  
+  inline wide_int neg () const;
+  inline wide_int neg (bool *overflow) const;
+  
+  wide_int parity () const;
+  wide_int popcount () const;
+  
+  template <typename T>
+  inline wide_int operator - (const T& c) const;
+  
+  /* Divison and mod.  These are the ones that are actually used, but
+     there are a lot of them.  */
+  
+  template <typename T>
+  inline wide_int div_trunc (const T &c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+  inline wide_int sdiv_trunc (const T &c) const;
+  template <typename T>
+  inline wide_int udiv_trunc (const T &c) const;
+  
+  template <typename T>
+  inline wide_int div_floor (const T &c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+  inline wide_int udiv_floor (const T &c) const;
+  template <typename T>
+  inline wide_int sdiv_floor (const T &c) const;
+  template <typename T>
+  inline wide_int div_ceil (const T &c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+  inline wide_int div_round (const T &c, SignOp sgn, bool *overflow = 0) const;
+  
+  template <typename T>
+  inline wide_int divmod_trunc (const T &c, wide_int *mod, SignOp sgn) const;
+  template <typename T>
+  inline wide_int sdivmod_trunc (const T &c, wide_int *mod) const;
+  template <typename T>
+  inline wide_int udivmod_trunc (const T &c, wide_int *mod) const;
+  
+  template <typename T>
+  inline wide_int divmod_floor (const T &c, wide_int *mod, SignOp sgn) const;
+  template <typename T>
+  inline wide_int sdivmod_floor (const T &c, wide_int *mod) const;
+  
+  template <typename T>
+  inline wide_int mod_trunc (const T &c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+  inline wide_int smod_trunc (const T &c) const;
+  template <typename T>
+  inline wide_int umod_trunc (const T &c) const;
+  
+  template <typename T>
+  inline wide_int mod_floor (const T &c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+  inline wide_int umod_floor (const T &c) const;
+  template <typename T>
+  inline wide_int mod_ceil (const T &c, SignOp sgn, bool *overflow = 0) const;
+  template <typename T>
+  inline wide_int mod_round (const T &c, SignOp sgn, bool *overflow = 0) const;
+  
+  /* Shifting rotating and extracting.  */
+  HOST_WIDE_INT extract_to_hwi (int offset, int width) const;
+  
+  template <typename T>
+  inline wide_int lshift (const T &c, unsigned int bitsize = 0,
+			  unsigned int precision = 0,
+			  ShiftOp z = NONE) const;
+
+  template <typename T>
+  inline wide_int lrotate (const T &c) const;
+  inline wide_int lrotate (unsigned HOST_WIDE_INT y) const;
+
+  template <typename T>
+  inline wide_int rshift (const T &c, SignOp sgn, 
+			  unsigned int bitsize = 0,
+			  ShiftOp z = NONE) const;
+  template <typename T>
+  inline wide_int rshiftu (const T &c, unsigned int bitsize = 0,
+			   ShiftOp z = NONE) const;
+  template <typename T>
+  inline wide_int rshifts (const T &c, unsigned int bitsize = 0,
+			   ShiftOp z = NONE) const;
+
+  template <typename T>
+  inline wide_int rrotate (const T &c) const;
+  inline wide_int rrotate (unsigned HOST_WIDE_INT y) const;
+
+  char *dump (char* buf) const;
+ private:
+
+  /* 
+   * Internal versions that do the work if the values do not fit in a
+   * HWI.
+   */ 
+
+  /* Comparisons */
+  bool eq_p_large (const HOST_WIDE_INT *, unsigned int) const;
+  static bool lts_p_large (const HOST_WIDE_INT *, unsigned int, 
+			   const HOST_WIDE_INT *, unsigned int,
+			   unsigned int);
+  int cmps_large (const HOST_WIDE_INT *, unsigned int) const;
+  static bool ltu_p_large (const HOST_WIDE_INT *, unsigned int, 
+			   const HOST_WIDE_INT *, unsigned int);
+  int cmpu_large (const HOST_WIDE_INT *, unsigned int) const;
+
+  /* Logicals.  */
+  wide_int and_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int and_not_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int or_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int or_not_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int xor_large (const HOST_WIDE_INT *, unsigned int) const;
+
+  /* Arithmetic */
+  wide_int add_large (const HOST_WIDE_INT *, unsigned int) const;
+  wide_int sub_large (const HOST_WIDE_INT *, unsigned int) const;
+
+  wide_int lshift_large (unsigned int cnt, unsigned int res_prec) const;
+  wide_int rshiftu_large (unsigned int cnt) const;
+  wide_int rshifts_large (unsigned int cnt) const;
+
+  static wide_int
+  mul_internal (bool high, bool full, 
+		const wide_int *op1, const HOST_WIDE_INT *op2, unsigned int op2len,
+		SignOp sgn,  bool *overflow, bool needs_overflow);
+  static void
+  divmod_internal_2 (unsigned HOST_HALF_WIDE_INT *b_quotient, 
+		     unsigned HOST_HALF_WIDE_INT *b_remainder,
+		     unsigned HOST_HALF_WIDE_INT *b_dividend, 
+		     unsigned HOST_HALF_WIDE_INT *b_divisor, 
+		     int m, int n);
+  static wide_int
+  divmod_internal (bool compute_quotient, 
+		   const wide_int *dividend, const HOST_WIDE_INT *, unsigned int,
+		   SignOp sgn, wide_int *remainder,
+		   bool compute_remainder, 
+		   bool *overflow);
+
+
+  /* Private utility routines.  */
+  wide_int decompress (unsigned int target, unsigned int precision) const;
+  void canonize ();
+  static inline int trunc_shift (const HOST_WIDE_INT *cnt, unsigned int len, 
+				 unsigned int bitsize, ShiftOp z);
+
+  template <typename T>
+  static inline bool
+  top_bit_set (T x) {
+    return (x >> (sizeof (x)*8 - 1)) != 0;
+  }
+
+  /* The following template and its overrides are used for the second
+     operand of binary functions.  They access the value are package
+     it so that the operation can be done.  These have been
+     implemented so that pointer copying is done from the rep of the
+     second operand rather than actual data copying.  This is safe
+     even for garbage collected objects since the value is immediately
+     throw away.  
+
+     The first two templates match all integers.  */
+
+  template <typename T>
+  static inline const HOST_WIDE_INT* 
+  to_shwi2 (HOST_WIDE_INT *s, unsigned int *l, unsigned int *p, const T& x)
+  {
+    s[0] = x;
+    if (~(T)0 < (T)0
+	|| sizeof (T) < sizeof (HOST_WIDE_INT)
+	|| ! top_bit_set (x))
+      {
+	*l = 1;
+      }
+    else
+      {
+	s[1] = 0;
+	*l = 2;	  
+      }
+    *p = 0;
+    return s;
+  }
+};
+
+template <>
+inline const HOST_WIDE_INT*
+wide_int::to_shwi2 (HOST_WIDE_INT *s ATTRIBUTE_UNUSED,
+		    unsigned int *l, unsigned int *p, const wide_int &y)
+{
+  *l = y.len;
+  *p = y.precision;
+  return y.val;
+}
+
+  
+/* This overload may just return the pointer to the value and set
+   the length.  */
+template<>
+inline const HOST_WIDE_INT*
+wide_int::to_shwi2 (HOST_WIDE_INT *s ATTRIBUTE_UNUSED,
+		    unsigned int *l, unsigned int *p, const const_tree& tcst)
+{
+  /* This is rather complex now, in the future when the rep for tree
+     cst is changed, it will be just a pointer and len copy.  */
+  tree type = TREE_TYPE (tcst);
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (prec > HOST_BITS_PER_WIDE_INT)
+    *l = 2;
+  else
+    {
+      if (prec == HOST_BITS_PER_WIDE_INT
+	  && TYPE_UNSIGNED (type)
+	  && (HOST_WIDE_INT)TREE_INT_CST_LOW (tcst) < 0)
+	*l = 2;
+      else
+	*l = 1;
+    }
+
+  *p = prec;
+  return (const HOST_WIDE_INT*)&TREE_INT_CST_LOW (tcst);
+}
+
+/* This is used to bundle an rtx and a mode together so that the pair
+   can be used as the second operand of a wide int expression.  If we
+   ever put modes into rtx integer constants, this should go away and
+   then just pass an rtx in.  */
+typedef std::pair<rtx, enum machine_mode> rtx_mode_t;
+
+/* There should logically be an overload for rtl here, but it cannot
+   be here because of circular include issues.  It is in rtl.h.  */
+template<>
+inline const HOST_WIDE_INT*
+wide_int::to_shwi2 (HOST_WIDE_INT *s ATTRIBUTE_UNUSED,
+		    unsigned int *l, unsigned int *p,
+		    const rtx_mode_t& rp);
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with precision
+   taken from MODE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, enum machine_mode mode)
+{
+  return wide_int::set_bit_in_zero (bitpos, GET_MODE_PRECISION (mode));
+}
+
+/* Insert a 1 bit into 0 at BITPOS producing an number with precision
+   taken from TYPE.  */
+
+wide_int
+wide_int::set_bit_in_zero (unsigned int bitpos, const_tree type)
+{
+
+  return wide_int::set_bit_in_zero (bitpos, TYPE_PRECISION (type));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with precision
+   taken from MODE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, enum machine_mode mode)
+{
+  return wide_int::mask (width, negate, GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask where the lower WIDTH bits are ones and the
+   bits above that up to the precision are zeros.  The result is
+   inverted if NEGATE is true.  The result is made with precision
+   taken from TYPE.  */
+
+wide_int
+wide_int::mask (unsigned int width, bool negate, const_tree type)
+{
+
+  return wide_int::mask (width, negate, TYPE_PRECISION (type));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the bits
+   above that up to the precision are zeros.  The result is inverted
+   if NEGATE is true.  The result is made with precision taken from
+   MODE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, enum machine_mode mode)
+{
+  return wide_int::shifted_mask (start, width, negate,
+				 GET_MODE_PRECISION (mode));
+}
+
+/* Return a result mask of WIDTH ones starting at START and the bits
+   above that up to the precision are zeros.  The result is inverted
+   if NEGATE is true.  The result is made with precision taken from
+   TYPE.  */
+
+wide_int
+wide_int::shifted_mask (unsigned int start, unsigned int width, 
+			bool negate, const_tree type)
+{
+
+  return wide_int::shifted_mask (start, width, negate,
+				 TYPE_PRECISION (type));
+}
+
+/* Produce 0 or -1 that is the smear of the sign bit.  */
+
+HOST_WIDE_INT
+wide_int::sign_mask () const
+{
+  int i = len - 1;
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    return ((val[0] << (HOST_BITS_PER_WIDE_INT - precision))
+	    >> (HOST_BITS_PER_WIDE_INT - 1));
+
+  /* VRP appears to be badly broken and this is a very ugly fix.  */
+  if (i >= 0)
+    return val[i] >> (HOST_BITS_PER_WIDE_INT - 1);
+
+  gcc_unreachable ();
+#if 0
+  return val[len - 1] >> (HOST_BITS_PER_WIDE_INT - 1);
+#endif
+}
+
+/* Conversions */
+
+/* Convert OP0 into a wide_int with parameters taken from TYPE.  If
+   the value does not fit, set OVERFLOW.  */
+
+wide_int
+wide_int::from_hwi (HOST_WIDE_INT op0, const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+
+  if (TYPE_UNSIGNED (type))
+    return wide_int::from_uhwi (op0, prec);
+  else
+    return wide_int::from_shwi (op0, prec);
+}
+
+/* Convert signed OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_shwi (HOST_WIDE_INT op0, enum machine_mode mode)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_shwi (op0, prec);
+}
+
+/* Convert unsigned OP0 into a wide_int with parameters taken from
+   MODE. If the value does not fit, set OVERFLOW. */
+
+wide_int
+wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode mode)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+
+  return wide_int::from_uhwi (op0, prec);
+}
+
+/* Return THIS as a signed HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+HOST_WIDE_INT 
+wide_int::to_shwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec == 0)
+    prec = precision;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = sext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+/* Return THIS as an unsigned HOST_WIDE_INT.  If THIS does not fit in
+   PREC, the information is lost. */
+
+unsigned HOST_WIDE_INT 
+wide_int::to_uhwi (unsigned int prec) const
+{
+  HOST_WIDE_INT result;
+
+  if (prec == 0)
+    prec = precision;
+
+  if (prec < HOST_BITS_PER_WIDE_INT)
+    result = zext_hwi (val[0], prec);
+  else
+    result = val[0];
+
+  return result;
+}
+
+
+/* Min and Max value helpers.  */
+
+/* Produce the largest number that is represented in MODE. The
+   precision are taken from mode.  SGN must be SIGNED or
+   UNSIGNED.  */
+
+wide_int
+wide_int::max_value (enum machine_mode mode, SignOp sgn)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+  return max_value (prec, sgn, prec);
+}
+
+/* Produce the largest number that is represented in TYPE. The
+   precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::max_value (const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  return max_value (prec, TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED, prec);
+}
+
+/* Produce the smallest number that is represented in MODE. The
+   precision are taken from mode.  SGN must be SIGNED or UNSIGNED.  */
+
+wide_int
+wide_int::min_value (enum machine_mode mode, SignOp sgn)
+{
+  unsigned int prec = GET_MODE_PRECISION (mode);
+  return min_value (prec, sgn, prec);
+}
+
+/* Produce the smallest number that is represented in TYPE. The
+   precision and sign are taken from TYPE.  */
+
+wide_int
+wide_int::min_value (const_tree type)
+{
+  unsigned int prec = TYPE_PRECISION (type);
+  return min_value (prec, TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED, prec);
+}
+
+
+/* Small constants.  */
+
+/* Return a wide int of -1 with precision PREC.  */
+
+wide_int
+wide_int::minus_one (unsigned int prec)
+{
+  return wide_int::from_shwi (-1, prec);
+}
+
+/* Return a wide int of 0 with precision PREC.  */
+
+wide_int
+wide_int::zero (unsigned int prec)
+{
+  return wide_int::from_shwi (0, prec);
+}
+
+/* Return a wide int of 1 with precision PREC.  */
+
+wide_int
+wide_int::one (unsigned int prec)
+{
+  return wide_int::from_shwi (1, prec);
+}
+
+/* Return a wide int of 2 with precision PREC.  */
+
+wide_int
+wide_int::two (unsigned int prec)
+{
+  return wide_int::from_shwi (2, prec);
+}
+
+/* Public accessors for the interior of a wide int.  */
+
+/* Get the number of host wide ints actually represented within the
+   wide int.  */
+
+unsigned short
+wide_int::get_len () const
+{
+  return len;
+}
+
+/* Get precision of the value represented within the wide int.  */
+
+unsigned int
+wide_int::get_precision () const
+{
+  return precision;
+}
+
+/* Get a particular element of the wide int.  */
+
+HOST_WIDE_INT
+wide_int::elt (unsigned int i) const
+{
+  return i >= len ? sign_mask () : val[i];
+}
+
+/* Return true if THIS is -1.  */
+
+bool
+wide_int::minus_one_p () const
+{
+  return len == 1 && val[0] == (HOST_WIDE_INT)-1;
+}
+
+/* Return true if THIS is 0.  */
+
+bool
+wide_int::zero_p () const
+{
+  return len == 1 && val[0] == 0;
+}
+
+/* Return true if THIS is 1.  */
+
+bool
+wide_int::one_p () const
+{
+  return len == 1 && val[0] == 1;
+}
+
+/* Return true if THIS is negative.  */
+
+bool
+wide_int::neg_p () const
+{
+  return sign_mask () != 0;
+}
+
+/*
+ * Comparisons, note that only equality is an operator.  The other
+ * comparisons cannot be operators since they are inherently signed or
+ * unsigned and C++ has no such operators.
+ */
+
+/* Return true if THIS == OP1.  */
+
+template <typename T>
+bool
+wide_int::operator == (const T &c) const
+{
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  if (precision < HOST_BITS_PER_WIDE_INT)
+    {
+      unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT)1 << precision) - 1;
+      result = (val[0] & mask) == (s[0] & mask);
+    }
+  else if (precision == HOST_BITS_PER_WIDE_INT)
+      result = val[0] == s[0];
+  else
+    result = eq_p_large (s, cl);
+
+  if (result)
+    gcc_assert (len == cl);
+
+  return result;
+}
+
+/* Return true if THIS is not equal to OP1. */ 
+
+template <typename T>
+bool
+wide_int::operator != (const T &c) const
+{
+  return !(*this == c);
+}  
+
+/* Return true if THIS is less than OP1.  Signness is indicated by
+   OP.  */
+
+template <typename T>
+bool
+wide_int::lt_p (const T &c, SignOp op) const
+{
+  if (op == SIGNED)
+    return lts_p (c);
+  else
+    return ltu_p (c);
+}  
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+template <typename T>
+bool
+wide_int::lts_p (const T &c) const
+{
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    /* The values are already logically sign extended.  */
+    result = val[0] < s[0];
+  else
+    result = lts_p_large (val, len, s, cl, precision);
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+template <typename T>
+bool
+wide_int::ltu_p (const T &c) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (s[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = s[0];
+	}
+
+      result = x0 < x1;
+    }
+  else
+    result = ltu_p_large (val, len, s, cl);
+  return result;
+}
+
+/* Return true if THIS is greater than OP1.  Signness is indicated by
+   OP.  */
+
+template <typename T>
+bool
+wide_int::gt_p (const T &c, SignOp op) const
+{
+  if (op == SIGNED)
+    return gts_p (c);
+  else
+    return gtu_p (c);
+}  
+
+/* Return true if THIS < OP1 using signed comparisons.  */
+
+template <typename T>
+bool
+wide_int::gts_p (const T &c) const
+{
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      result = val[0] > s[0];
+    }
+  else
+    /* Reverse the parms and use ltu.  */
+    result = lts_p_large (s, cl, val, len, precision);
+  return result;
+}
+
+/* Return true if THIS < OP1 using unsigned comparisons.  */
+
+template <typename T>
+bool
+wide_int::gtu_p (const T &c) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  bool result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (s[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = s[0];
+	}
+
+      result = x0 > x1;
+    }
+  else 
+    /* Reverse the parms and use ltu.  */
+    result = ltu_p_large (s, cl, val, len);
+  return result;
+}
+
+
+/* Return -1 0 or 1 depending on how THIS compares with OP1.  Signness
+   is indicated by OP.  */
+
+template <typename T>
+int
+wide_int::cmp (const T &c, SignOp op) const
+{
+  if (op == SIGNED)
+    return cmps (c);
+  else
+    return cmpu (c);
+}  
+
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   signed compares.  */
+
+template <typename T>
+int
+wide_int::cmps (const T &c) const
+{
+  int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* The values are already logically sign extended.  */
+      if (val[0] < s[0])
+	result = -1;
+      else if (val[0] > s[0])
+	result = 1;
+      else 
+	result = 0;
+    }
+  else
+    result = cmps_large (s, cl);
+  return result;
+}
+
+/* Returns -1 if THIS < OP1, 0 if THIS == OP1 and 1 if A > OP1 using
+   unsigned compares.  */
+
+template <typename T>
+int
+wide_int::cmpu (const T &c) const
+{
+  unsigned HOST_WIDE_INT x0;
+  unsigned HOST_WIDE_INT x1;
+  int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	{
+	  x0 = zext_hwi (val[0], precision);
+	  x1 = zext_hwi (s[0], precision);
+	}
+      else
+	{
+	  x0 = val[0];
+	  x1 = s[0];
+	}
+
+      if (x0 < x1)
+	result = -1;
+      else if (x0 == x1)
+	result = 0;
+      else
+	result = 1;
+    }
+  else
+    result = cmpu_large (s, cl);
+  return result;
+}
+
+
+/* Return the signed or unsigned min of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::min (const T &c, SignOp sgn) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  if (sgn == SIGNED)
+    return lts_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+  else
+    return ltu_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the signed or unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::min (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return lts_p (op1) ? (*this) : op1;
+  else
+    return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed or unsigned max of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::max (const T &c, SignOp sgn) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  if (sgn == SIGNED)
+    return gts_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+  else
+    return gtu_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the signed or unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::max (const wide_int &op1, SignOp sgn) const
+{
+  if (sgn == SIGNED)
+    return gts_p (op1) ? (*this) : op1;
+  else
+    return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed min of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::smin (const T &c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  return lts_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the signed min of THIS and OP1. */
+
+wide_int
+wide_int::smin (const wide_int &op1) const
+{
+  return lts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the signed max of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::smax (const T &c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  return gts_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the signed max of THIS and OP1. */
+
+wide_int
+wide_int::smax (const wide_int &op1) const
+{
+  return gts_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned min of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::umin (const T &c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  return ltu_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the unsigned min of THIS and OP1. */
+
+wide_int
+wide_int::umin (const wide_int &op1) const
+{
+  return ltu_p (op1) ? (*this) : op1;
+}  
+
+/* Return the unsigned max of THIS and OP1. */
+
+template <typename T>
+wide_int
+wide_int::umax (const T &c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  return gtu_p (c) ? (*this) : wide_int::from_array (s, cl, precision, false);
+}  
+
+/* Return the unsigned max of THIS and OP1. */
+
+wide_int
+wide_int::umax (const wide_int &op1) const
+{
+  return gtu_p (op1) ? (*this) : op1;
+}  
+
+/* Return true if THIS has the sign bit set to 1 and all other bits are
+   zero.  */
+
+bool
+wide_int::only_sign_bit_p () const
+{
+  return only_sign_bit_p (precision);
+}
+
+/* Return true if THIS fits in a HOST_WIDE_INT with no loss of
+   precision.  */
+
+bool
+wide_int::fits_shwi_p () const
+{
+  return len == 1;
+}
+
+/* Return true if THIS fits in an unsigned HOST_WIDE_INT with no loss
+   of precision.  */
+
+bool
+wide_int::fits_uhwi_p () const
+{
+  return len == 1 
+    || (len == 2 && val[1] == 0);
+}
+
+/* Return THIS extended to PREC.  The signness of the extension is
+   specified by OP.  */
+
+wide_int 
+wide_int::ext (unsigned int prec, SignOp z) const
+{
+  if (z == UNSIGNED)
+    return zext (prec);
+  else
+    return sext (prec);
+}
+
+/* Return THIS forced to the size PREC.  This is sign extended if
+   needed. */
+
+wide_int 
+wide_int::sforce_to_size (unsigned int prec) const
+{
+  return force_to_size (prec, SIGNED);
+}
+
+/* Return THIS forced to the size PREC.  This is zero extended if
+   needed. */
+
+wide_int 
+wide_int::zforce_to_size (unsigned int prec) const
+{
+  return force_to_size (prec, UNSIGNED);
+}
+
+/*
+ * Logicals.
+ */
+
+/* Return THIS & OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator & (const T &c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] & s[0];
+    }
+  else
+    result = and_large (s, cl);
+  return result;
+}
+
+
+/* Return THIS & ~OP1.  */
+
+template <typename T>
+wide_int
+wide_int::and_not (const T &c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] & ~s[0];
+    }
+  else
+    result = and_not_large (s, cl);
+  return result;
+}
+
+
+/* Return the logical negation (bitwise complement) of THIS.  */
+
+wide_int
+wide_int::operator ~ () const
+{
+  wide_int result;
+  int l0 = len - 1;
+
+  result.len = len;
+  result.precision = precision;
+
+  while (l0 >= 0)
+    {
+      result.val[l0] = ~val[l0];
+      l0--;
+    }
+  return result;
+}
+
+/* Return THIS | OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator | (const T &c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] | s[0];
+    }
+  else
+    result = or_large (s, cl);
+  return result;
+}
+
+
+/* Return THIS | ~OP1.  */
+
+template <typename T>
+wide_int
+wide_int::or_not (const T &c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] | ~s[0];
+    }
+  else
+    result = or_not_large (s, cl);
+  return result;
+}
+
+
+/* Return THIS ^ OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator ^ (const T &c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] ^ s[0];
+    }
+  else
+    result = xor_large (s, cl);
+  return result;
+}
+
+/*
+ * Integer arithmetic
+ */
+
+/* Return THIS + OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator + (const T &c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] + s[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = add_large (s, cl);
+  return result;
+}
+
+/* Multiply THIS and OP1.  The result is the same precision as the
+   operands, so there is no reason for signed or unsigned
+   versions.  */
+
+template <typename T>
+wide_int
+wide_int::operator * (const T &c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+  bool overflow = false;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] * s[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = mul_internal (false, false, this, s, cl, UNSIGNED, &overflow, false);
+  return result;
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.
+   OVERFLOW is set true if the result overflows.  */
+
+template <typename T>
+wide_int 
+wide_int::mul (const T &c, SignOp sgn, bool *overflow) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  return mul_internal (false, false, this, s, cl, sgn, overflow, true);
+}
+
+/* Signed multiply THIS and OP1.  The result is the same precision as
+   the operands.  OVERFLOW is set true if the result overflows.  */
+
+template <typename T>
+wide_int
+wide_int::smul (const T &c, bool *overflow) const
+{
+  return mul (c, SIGNED, overflow);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is the same precision
+   as the operands.  OVERFLOW is set true if the result overflows.  */
+
+template <typename T>
+wide_int
+wide_int::umul (const T &c, bool *overflow) const
+{
+  return mul (c, UNSIGNED, overflow);
+}
+
+/* Multiply THIS and OP1.  The signess is specified with SGN.  The
+   result is twice the precision as the operands.  The signess is
+   specified with SGN.  */
+
+template <typename T>
+wide_int
+wide_int::mul_full (const T &c, SignOp sgn) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  return mul_internal (false, true, this, s, cl, sgn, 0, false);
+}
+
+/* Signed multiply THIS and OP1.  The result is twice the precision as
+   the operands.  */
+
+template <typename T>
+wide_int
+wide_int::smul_full (const T &c) const
+{
+  return mul_full (c, SIGNED);
+}
+
+/* Unsigned multiply THIS and OP1.  The result is twice the precision
+   as the operands.  */
+
+template <typename T>
+wide_int
+wide_int::umul_full (const T &c) const
+{
+  return mul_full (c, UNSIGNED);
+}
+
+/* Multiply THIS and OP1 and return the high part of that result.  The
+   signess is specified with SGN.  The result is the same precision as
+   the operands.  The mode is the same mode as the operands.  The
+   signess is specified with y.  */
+
+template <typename T>
+wide_int
+wide_int::mul_high (const T &c, SignOp sgn) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  return mul_internal (true, false, this, s, cl, sgn, 0, false);
+}
+
+/* Negate THIS.  */
+
+wide_int
+wide_int::neg () const
+{
+  wide_int z = wide_int::from_shwi (0, precision);
+  return z - *this;
+}
+
+/* Negate THIS.  Set overflow if the value cannot be negated.  */
+
+wide_int
+wide_int::neg (bool *overflow) const
+{
+  wide_int z = wide_int::from_shwi (0, precision);
+  if (only_sign_bit_p ())
+    *overflow = true;
+
+  return z - *this;
+}
+
+/* Return THIS - OP1.  */
+
+template <typename T>
+wide_int
+wide_int::operator - (const T& c) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+  
+  if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.len = 1;
+      result.precision = precision;
+      result.val[0] = val[0] - s[0];
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	result.val[0] = sext_hwi (result.val[0], precision);
+    }
+  else
+    result = sub_large (s, cl);
+  return result;
+}
+
+
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is truncated.
+   Overflow is set to true if the result overflows, otherwise it is
+   not set.  */
+template <typename T>
+wide_int
+wide_int::div_trunc (const T &c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+  
+  return divmod_internal (true, this, s, cl, sgn, 
+			  &remainder, false, overflow);
+}
+
+/* Signed divide with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::sdiv_trunc (const T &c) const
+{
+  return div_trunc (c, SIGNED);
+}
+
+/* Unsigned divide with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::udiv_trunc (const T &c) const
+{
+  return div_trunc (c, UNSIGNED);
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is floor
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::div_floor (const T &c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return quotient - 1;
+  return quotient;
+}
+
+/* Unsigned divide with floor truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::udiv_floor (const T &c) const
+{
+  bool overflow;
+
+  return div_floor (c, UNSIGNED, &overflow);
+}
+
+/* Signed divide with floor truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::sdiv_floor (const T &c) const
+{
+  bool overflow;
+
+  return div_floor (c, SIGNED, &overflow);
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is ceil
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::div_ceil (const T &c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return quotient;
+      else
+	return quotient + 1;
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS.  The result is the same size as the
+   operands.  The sign is specified in SGN.  The output is round
+   truncated.  Overflow is set to true if the result overflows,
+   otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::div_round (const T &c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+  if (!remainder.zero_p ())
+    {
+      wide_int divisor = wide_int::from_array (s, cl, precision);
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu_large (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return quotient - 1;
+	      else 
+		return quotient + 1;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu_large (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return quotient + 1;
+	}
+    }
+  return quotient;
+}
+
+/* Divide DIVISOR into THIS producing both the quotient and remainder.
+   The result is the same size as the operands.  The sign is specified
+   in SGN.  The output is truncated.  */
+
+template <typename T>
+wide_int
+wide_int::divmod_trunc (const T &c, wide_int *remainder, SignOp sgn) const
+{
+  bool overflow = false;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  return divmod_internal (true, this, s, cl, sgn, 
+			  remainder, true, &overflow);
+}
+
+/* Signed divide/mod with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::sdivmod_trunc (const T &c, wide_int *mod) const
+{
+  return divmod_trunc (c, mod, SIGNED);
+}
+
+/* Unsigned divide/mod with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::udivmod_trunc (const T &c, wide_int *mod) const
+{
+  return divmod_trunc (c, mod, UNSIGNED);
+}
+
+/* Divide DIVISOR into THIS.  The remainder is also produced in
+   REMAINDER.  The result is the same size as the operands.  The sign
+   is specified in SGN.  The output is floor truncated.  Overflow is
+   set to true if the result overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::divmod_floor (const T &c, wide_int *remainder, SignOp sgn) const
+{
+  wide_int quotient;
+  bool overflow = false;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      remainder, true, &overflow);
+  if (sgn == SIGNED && quotient.neg_p () && !(*remainder).zero_p ())
+    {
+      *remainder = *remainder - wide_int::from_array (s, cl, precision);
+      return quotient - 1;
+    }
+  return quotient;
+}
+
+/* Signed divide/mod with floor truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::sdivmod_floor (const T &c, wide_int *mod) const
+{
+  return divmod_floor (c, mod, SIGNED);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::mod_trunc (const T &c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  divmod_internal (true, this, s, cl, sgn, 
+			  &remainder, true, overflow);
+  return remainder;
+}
+
+/* Signed mod with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::smod_trunc (const T &c) const
+{
+  return mod_trunc (c, SIGNED);
+}
+
+/* Unsigned mod with truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::umod_trunc (const T &c) const
+{
+  return mod_trunc (c, UNSIGNED);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is floor truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::mod_floor (const T &c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+
+  if (sgn == SIGNED && quotient.neg_p () && !remainder.zero_p ())
+    return remainder - wide_int::from_array (s, cl, precision);
+  return remainder;
+}
+
+/* Unsigned mod with floor truncation of result.  */
+
+template <typename T>
+wide_int
+wide_int::umod_floor (const T &c) const
+{
+  bool overflow;
+
+  return mod_floor (c, UNSIGNED, &overflow);
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is the
+   same size as the operands.  The sign is specified in SGN.  The
+   output is ceil truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::mod_ceil (const T &c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      if (sgn == UNSIGNED || quotient.neg_p ())
+	return remainder;
+      else
+	return remainder - wide_int::from_array (s, cl, precision);
+    }
+  return remainder;
+}
+
+/* Divide DIVISOR into THIS producing the remainder.  The result is
+   the same size as the operands.  The sign is specified in SGN.  The
+   output is round truncated.  Overflow is set to true if the result
+   overflows, otherwise it is not set.  */
+
+template <typename T>
+wide_int
+wide_int::mod_round (const T &c, SignOp sgn, bool *overflow) const
+{
+  wide_int remainder;
+  wide_int quotient;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+  gcc_checking_assert (prec == 0 || prec == precision);
+
+  quotient = divmod_internal (true, this, s, cl, sgn, 
+			      &remainder, true, overflow);
+
+  if (!remainder.zero_p ())
+    {
+      wide_int divisor = wide_int::from_array (s, cl, precision);
+      if (sgn == SIGNED)
+	{
+	  wide_int p_remainder = remainder.neg_p () ? remainder.neg () : remainder;
+	  wide_int p_divisor = divisor.neg_p () ? divisor.neg () : divisor;
+	  p_divisor = p_divisor.rshiftu_large (1);
+	  
+	  if (p_divisor.gts_p (p_remainder)) 
+	    {
+	      if (quotient.neg_p ())
+		return remainder + divisor;
+	      else 
+		return remainder - divisor;
+	    }
+	}
+      else
+	{
+	  wide_int p_divisor = divisor.rshiftu_large (1);
+	  if (p_divisor.gtu_p (remainder))
+	    return remainder - divisor;
+	}
+    }
+  return remainder;
+}
+
+
+/* If SHIFT_COUNT_TRUNCATED is defined, truncate CNT.   
+
+   At first look, the shift truncation code does not look right.
+   Shifts (and rotates) are done according to the precision of the
+   mode but the shift count is truncated according to the bitsize of
+   the mode.  This is how real hardware works (Knuth's mix machine is
+   the only known exception to this rule, but it was never real).
+
+   On an ideal machine, like Knuth's mix machine, a shift count is a
+   word long and all of the bits of that word are examined to compute
+   the shift amount.  But on real hardware, especially on machines
+   with fast (single cycle shifts) that takes too long.  On these
+   machines, the amount of time to perform a shift dictates the cycle
+   time of the machine so corners are cut to keep this fast.  A
+   comparison of an entire 64 bit word would take something like 6
+   gate delays before the shifting can even start.
+
+   So real hardware only looks at a small part of the shift amount.
+   On ibm machines, this tends to be 1 more than what is necessary to
+   encode the shift amount.  The rest of the world looks at only the
+   minimum number of bits.  This means that only 3 gate delays are
+   necessary to set up the shifter.
+
+   On the other hand, right shifts and rotates must be according to
+   the precision or the operation does not make any sense. 
+
+   This function is called in two contexts.  If OP == TRUNC, this
+   function provides a count that matches the semantics of the target
+   machine depending on the value of SHIFT_COUNT_TRUNCATED.  Note that
+   if SHIFT_COUNT_TRUNCATED is not defined, this function may produce
+   -1 as a value if the shift amount is greater than the bitsize of
+   the mode.  -1 is a surrogate for a very large amount.
+
+   If OP == NONE, then this function always truncates the shift value
+   to the bitsize because this shifting operation is a function that
+   is internal to GCC.  */
+
+inline int
+wide_int::trunc_shift (const HOST_WIDE_INT *cnt, unsigned int len ATTRIBUTE_UNUSED,
+		       unsigned int bitsize, ShiftOp trunc_op)
+{
+  if (trunc_op == TRUNC)
+    {
+      gcc_checking_assert (bitsize != 0);
+#ifdef SHIFT_COUNT_TRUNCATED
+      return cnt[0] & (bitsize - 1);
+#else
+      if (cnt[0] < bitsize && cnt[0] >= 0 && len == 1)
+	return cnt[0];
+      else 
+	return -1;
+#endif
+    }
+  else if (bitsize == 0)
+    return cnt[0];
+  else
+    return cnt[0] & (bitsize - 1);
+}
+
+/* Left shift THIS by C.  See the definition of Op.TRUNC for how to
+   set TRUNC_OP.  Since this is used internally, it has the ability to
+   specify the BITSIZE  and PRECISION independently.  This is useful
+   when inserting a small value into a larger one.  */
+
+template <typename T>
+wide_int
+wide_int::lshift (const T &c, unsigned int bitsize, 
+		  unsigned int res_prec, ShiftOp trunc_op) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+  HOST_WIDE_INT shift;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+
+  if (res_prec == 0)
+    res_prec = precision;
+
+  shift = trunc_shift (s, cl, bitsize, trunc_op);
+  if (shift == -1)
+    result = wide_int::zero (precision);
+  else if (shift == 0 && res_prec == precision)
+    result = *this;
+  /* Handle the simple case quickly.   */
+  else if (res_prec <= HOST_BITS_PER_WIDE_INT)
+    {
+      result.precision = res_prec;
+      result.len = 1;
+      result.val[0] = val[0] << shift;
+    }
+  else
+    result = lshift_large (shift, res_prec);
+  return result;
+}
+
+/* Rotate THIS left by Y within its precision.  */
+
+template <typename T>
+wide_int
+wide_int::lrotate (const T &c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+
+  return lrotate ((unsigned HOST_WIDE_INT)s[0]);
+}
+
+
+/* Rotate THIS left by CNT within its precision.  */
+
+wide_int
+wide_int::lrotate (unsigned HOST_WIDE_INT cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (cnt);
+  right = rshiftu (precision - cnt);
+  result = left | right;
+
+  return result;
+}
+
+
+/* Right shift THIS by Y.  SGN indicates the sign.  TRUNC_OP indicates the
+   truncation option.  */
+
+template <typename T>
+wide_int
+wide_int::rshift (const T &c, SignOp sgn, 
+		  unsigned int bitsize, ShiftOp trunc_op) const
+{
+  if (sgn == UNSIGNED)
+    return rshiftu (c, bitsize, trunc_op);
+  else
+    return rshifts (c, bitsize, trunc_op);
+}
+
+
+/* Unsigned right shift THIS by CNT.  See the definition of Op.TRUNC
+   for how to set TRUNC_OP.  */
+
+template <typename T>
+wide_int
+wide_int::rshiftu (const T &c, unsigned int bitsize,
+		   ShiftOp trunc_op) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+  HOST_WIDE_INT shift;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+
+  shift = trunc_shift (s, cl, bitsize, trunc_op);
+  
+  if (shift == 0)
+    result = copy ();
+  else if (shift == -1)
+    result = wide_int::zero (precision);
+  else if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* Handle the simple case quickly.   */
+      unsigned HOST_WIDE_INT x = val[0];
+
+      result.precision = precision;
+      result.len = 1;
+
+      if (precision < HOST_BITS_PER_WIDE_INT)
+	x = zext_hwi (x, precision);
+
+      result.val[0] = x >> shift;
+    }
+  else 
+    result = rshiftu_large (shift);
+  return result;
+}
+
+/* Signed right shift THIS by CNT.  See the definition of Op.TRUNC for
+   how to set TRUNC_OP.  */
+
+template <typename T>
+wide_int
+wide_int::rshifts (const T &c, unsigned int bitsize,
+		   ShiftOp trunc_op) const
+{
+  wide_int result;
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+  HOST_WIDE_INT shift;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+
+  shift = trunc_shift (s, cl, bitsize, trunc_op);
+  
+  if (shift == 0)
+    result = copy ();
+  else if (shift == -1)
+    result = wide_int::zero (precision);
+  else if (precision <= HOST_BITS_PER_WIDE_INT)
+    {
+      /* Handle the simple case quickly.   */
+      HOST_WIDE_INT x = val[0];
+
+      result.precision = precision;
+      result.len = 1;
+      result.val[0] = x >> shift;
+    }
+  else 
+    result = rshifts_large (shift);
+  return result;
+}
+
+/* Rotate THIS right by Y within its precision.  */
+
+
+template <typename T>
+wide_int
+wide_int::rrotate (const T &c) const
+{
+  HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS];
+  const HOST_WIDE_INT *s;
+  unsigned int cl;
+  unsigned int prec;
+
+  s = to_shwi2 (ws, &cl, &prec, c);
+
+  return rrotate ((unsigned HOST_WIDE_INT) s[0]);
+}
+
+
+/* Rotate THIS left by CNT within its precision.  */
+
+wide_int
+wide_int::rrotate (unsigned HOST_WIDE_INT cnt) const
+{
+  wide_int left, right, result;
+
+  left = lshift (precision - cnt);
+  right = rshiftu (cnt);
+  result = left | right;
+
+  return result;
+}
+
+/* tree related routines.  */
+
+extern tree wide_int_to_tree (tree type, const wide_int &cst);
+extern tree wide_int_to_infinite_tree (tree type, const wide_int &cst, 
+				       unsigned int prec);
+extern tree force_fit_type_wide (tree, const wide_int &, int, bool);
+
+/* real related routines.  */
+extern wide_int real_to_integer (const REAL_VALUE_TYPE *, bool *, int);
+extern wide_int decimal_real_to_integer (const REAL_VALUE_TYPE *, bool *, int);
+
+
+/* Conversion to and from GMP integer representations.  */
+
+void mpz_set_wide_int (mpz_t, wide_int, bool);
+wide_int mpz_get_wide_int (const_tree, mpz_t, bool);
+#endif /* GENERATOR FILE */
+
+#endif /* WIDE_INT_H */

[-- Attachment #3: p4-7.clog --]
[-- Type: text/plain, Size: 340 bytes --]

2013-05-02  Kenneth Zadeck <zadeck@naturalbridge.com>

	* Makefile.in (wide-int.c, wide-int.h): New files.
	* rtl.h (get_rtx, get_mode): New accessors for rtx_mode_t.
	(wide_int::to_shwi2): new template.
	* wide-int.c: New file containing implementation of wide_int class.
	* wide-int.h: New file containing public spec for wide_int class.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 13:25                                                                                     ` Richard Biener
  2013-04-24 13:37                                                                                       ` Richard Sandiford
@ 2013-05-02 17:22                                                                                       ` Kenneth Zadeck
  1 sibling, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-05-02 17:22 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 12465 bytes --]

On 04/24/2013 08:09 AM, Richard Biener wrote:
> On Tue, Apr 16, 2013 at 10:17 PM, Kenneth Zadeck
> <zadeck@naturalbridge.com>  wrote:
>> Here is a refreshed version of the rtl changes for wide-int.   the only
>> change from the previous versions is that the wide-int binary operations
>> have been simplified to use the new wide-int binary templates.
> Looking for from_rtx calls (to see where we get the mode/precision from) I
> see for example
>
> -         o = rtx_to_double_int (outer);
> -         i = rtx_to_double_int (inner);
> -
> -         m = double_int::mask (width);
> -         i &= m;
> -         m = m.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
> -         i = i.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
> -         o = o.and_not (m) | i;
> -
> +
> +         o = (wide_int::from_rtx (outer, GET_MODE (SET_DEST (temp)))
> +              .insert (wide_int::from_rtx (inner, GET_MODE (dest)),
> +                       offset, width));
>
> where I'd rather have the original code preserved as much as possible
> and not introduce a new primitive wide_int::insert for this.  The conversion
> and review process will be much more error-prone if we do multiple
> things at once (and it might keep the wide_int initial interface leaner).
this code is doing an insertion.    the old code does it in a round 
about way since there was not an insert primitive in double-int.   I do 
not think that we should penalize ourselves forever because double-int 
did not have a robust interface.

> Btw, the wide_int::insert implementation doesn't assert anything about
> the inputs precision.  Instead it reads
>
> +  if (start + width >= precision)
> +    width = precision - start;
> +
> +  mask = shifted_mask (start, width, false, precision);
> +  tmp = op0.lshift (start, 0, precision, NONE);
> +  result = tmp & mask;
> +
> +  tmp = and_not (mask);
> +  result = result | tmp;
>
> which eventually ends up performing everything in target precision.  So
> we don't really care about the mode or precision of inner.
I added checking to make sure that the width of the value being inserted 
was less than or equal to it's precision.  But there is no reason make 
sure that both operands are the same.    I do believe that it is the 
correct decision to have the target precision be the same as the first 
operand for this.
> Then I see
>
> diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
> index ad03a34..531a7c1 100644
> @@ -180,6 +182,7 @@ typedef struct GTY(()) dw_val_struct {
>         HOST_WIDE_INT GTY ((default)) val_int;
>         unsigned HOST_WIDE_INT GTY ((tag
> ("dw_val_class_unsigned_const"))) val_unsigned;
>         double_int GTY ((tag ("dw_val_class_const_double"))) val_double;
> +      wide_int GTY ((tag ("dw_val_class_wide_int"))) val_wide;
>         dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
>         struct dw_val_die_union
>          {
>
> ick.  That makes dw_val_struct really large ... (and thus dw_attr_struct).
> You need to make this a pointer to a wide_int at least.
This was an incredible mess to fix, but we did it.    it required 
enhancements to the gty parser.   The changes are in the new patch. The 
changes are to gengtype-lex.l gengtype-parse.c
> -/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
> +/* Return a constant integer corresponding to target reading
>      GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
>
>   static rtx
>   c_readstr (const char *str, enum machine_mode mode)
>   {
> -  HOST_WIDE_INT c[2];
> +  wide_int c;
> ...
> -  return immed_double_const (c[0], c[1], mode);
> +
> +  c = wide_int::from_array (tmp, len, mode);
> +  return immed_wide_int_const (c, mode);
>   }
>
> err - what's this good for?  It doesn't look necessary as part of the initial
> wide-int conversion at least.  (please audit your patches for such cases)
it is good so that we never trip over this in the future.   (where the 
future is defined as what i need right now with wider modes and that is 
just around the corner for other ports that are starting to use OImode 
types.)    This patch makes the portable back end immune from issues 
that arise because of large types.   As i have said before, there is 
nothing in gcc that should be limited by the size of two HWIs.

> @@ -4994,12 +4999,12 @@ expand_builtin_signbit (tree exp, rtx target)
>
>     if (bitpos < GET_MODE_BITSIZE (rmode))
>       {
> -      double_int mask = double_int_zero.set_bit (bitpos);
> +      wide_int mask = wide_int::set_bit_in_zero (bitpos, rmode);
>
>         if (GET_MODE_SIZE (imode) > GET_MODE_SIZE (rmode))
>          temp = gen_lowpart (rmode, temp);
>         temp = expand_binop (rmode, and_optab, temp,
> -                          immed_double_int_const (mask, rmode),
> +                          immed_wide_int_const (mask, rmode),
>                             NULL_RTX, 1, OPTAB_LIB_WIDEN);
>       }
>     else
>
> Likewise.  I suppose you remove immed_double_int_const but I see no
> reason to do that.  It just makes your patch larger than necessary.
Like that code with the double int would work for OImode.
> [what was the reason again to have TARGET_SUPPORTS_WIDE_INT at all?
> It's supposed to be a no-op conversion, right?]
If target_supports_wide_int is non zero, then the port has been 
converted so that it expects that constant integers that require more 
than HOST_BITS_PER_WIDE_INT bits to represent to be in a CONST_WIDE_INT 
rather than sharing their representation with floating point in a 
DOUBLE_INT.   If the target has not been converted then it shares the 
rep of these larger integers with CONST_DOUBLE and is not expected to 
see any constants that cannot be represented in two HWIs.   So this 
patch covers the portable parts of the rtl code and converts all of the 
math so that there are no places where the portable parts will choke on 
large math, but it does that conversion in a way that the ports that 
have not yet converted continue to work properly.

Note that I did not say "see no change".  There are a fair number of 
places in the compiler where we have code that checked if the precision 
was less than or equal to HOST_BITS_PER_WIDE_INT and only did the 
transformation if that was true.    Unless I could see that this was 
only applied to values that are always small, like string lengths, i 
have converted them to use the wide-int api.    My goal here is to 
transform gcc from a compiler that does pretty well on things 64 bits or 
smaller, a lot less well on things in the range 65-128 bits and blows up 
or gets the wrong answer on things larger, to one that works uniformly 
well on all precisions that are supported by the target.

You said in a branch to this thread that:

I'd rather not have this patch-set introduce such subtle differences.

The changes are not subtle.   They are substantial and deliberate.    
The point of my work was never to introduce a prettier api, it was to 
make the compiler do reasonable things when the precision was larger 
than 64 bits and to keep it from doing brain dead things when the 
precision was larger than 128.   That is my primary concern here.   The 
rest of this is what had to be done to get there.

> @@ -95,38 +95,9 @@ plus_constant (enum machine_mode mode, rtx x,
> HOST_WIDE_INT c)
>
>     switch (code)
>       {
> -    case CONST_INT:
> -      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
> -       {
> -         double_int di_x = double_int::from_shwi (INTVAL (x));
> -         double_int di_c = double_int::from_shwi (c);
> -
> -         bool overflow;
> -         double_int v = di_x.add_with_sign (di_c, false, &overflow);
> -         if (overflow)
> -           gcc_unreachable ();
> -
> -         return immed_double_int_const (v, VOIDmode);
> -       }
> -
> -      return GEN_INT (INTVAL (x) + c);
> -
> -    case CONST_DOUBLE:
> -      {
> -       double_int di_x = double_int::from_pair (CONST_DOUBLE_HIGH (x),
> -                                                CONST_DOUBLE_LOW (x));
> -       double_int di_c = double_int::from_shwi (c);
> -
> -       bool overflow;
> -       double_int v = di_x.add_with_sign (di_c, false, &overflow);
> -       if (overflow)
> -         /* Sorry, we have no way to represent overflows this wide.
> -            To fix, add constant support wider than CONST_DOUBLE.  */
> -         gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT);
> -
> -       return immed_double_int_const (v, VOIDmode);
> -      }
> -
> +    CASE_CONST_SCALAR_INT:
> +      return immed_wide_int_const (wide_int::from_rtx (x, mode)
> +                                  + wide_int::from_shwi (c, mode), mode);
>
> you said you didn't want to convert CONST_INT to wide-int.  But the above
> is certainly a lot less efficient than before - given your change to support
> operator+ RTX even less efficient than possible.  The above also shows
> three 'mode' arguments while one to immed_wide_int_const would be
> enough (given it would truncate the arbitrary precision result from the
> addition to modes precision).
i did not say this and i certainly have no intention to not to do 
this.   What I did say was that I am going to preserve the rtl design to 
have two representations of rtl integer constants: one for the ones that 
fit into a single HWI and another for the ones that do not.

However, I believe that my code is faster than this code.   Note that my 
current patch looks more like

+    CASE_CONST_SCALAR_INT:
+      return immed_wide_int_const (wide_int::from_rtx (x, mode)
+                                  + c, mode);

This code turns into (when the constant is a CONST_INT):
1) convert x to a wide int
2) do an inline add of first element of the array in the wide-int with c;
3) sign extend past the precision if the modes precision is less that 
HOST_BITS_PER_WIDE_INT.
4) convert back.

I claim that it is cheaper because:
1) only one value is converted into a wide int and in the old code two 
values are converted to double-int
2) step 2 of the wide-int is cheaper than what is done in double-int.  
There is no carry code because we need to do two hwis of work and the 
conversion of c is basically free.  The cost of the rest of the steps 
are about the same.

This is one of the reasons that Richard and I are so vehemently opposed 
to your infinite precision idea.   If we did infinite precision then you 
would likely be correct, this could be more expensive.   But the finite 
precision implementation that we do means that we can short circuit the 
64 bit or less case with an inline add of two HWIs and be done.  Note 
that almost every operation in my wide-int has such a short circuit.

And of course that 64 bit or less case happens 99% of the time.

> That is, I see no reason to remove the CONST_INT case or the CONST_DOUBLE
> case.  [why is the above not in any way guarded with TARGET_SUPPORTS_WIDE_INT?]

The CASE_CONST_SCALAR_INT covers all possibilities.

> What happens with overflows in the wide-int case?  The double-int case
> asserted that there is no overflow across 2 * hwi precision, the wide-int
> case does not.  Still the wide-int case now truncates to 'mode' precision
> while the CONST_DOUBLE case did not.
>
> That's a change in behavior, no?  Effectively the code for CONST_INT
> and CONST_DOUBLE did "arbitrary" precision arithmetic (up to the
> precision they can encode) which wide-int changes.
>
> Can we in such cases please to a preparatory patch and change the
> CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
> mode precision first?  What does wide-int do with VOIDmode mode inputs?
> It seems to ICE on them for from_rtx and use garbage (0) for from_shwi.  Ugh.
> Btw, plus_constant asserts that mode is either VOIDmode (I suppose semantically
> do "arbitrary precision") or the same mode as the mode of x (I suppose
> semantically do "mode precision").  Neither the current nor your implementation
> seems to do something consistent here :/
>
> So please, for those cases (I suppose there are many more, eventually
> one of the reasons why you think that requiring a mode for all CONST_DOUBLEs
> is impossible), can we massage the current code to 1) document what is
> desired, 2) follow that specification with regarding to computation
> mode / precision
> and result mode / precision?
what richard said.   The only thing for me to add is to remind you that 
getting rid of that assert is why i am doing this work.
> Thanks,
> Richard.
>
>> kenny
>>


[-- Attachment #2: p5-7.diff --]
[-- Type: text/x-patch, Size: 138891 bytes --]

diff --git a/gcc/alias.c b/gcc/alias.c
index ef11c6a..ed5ceb4 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -1471,9 +1471,7 @@ rtx_equal_for_memref_p (const_rtx x, const_rtx y)
 
     case VALUE:
     CASE_CONST_UNIQUE:
-      /* There's no need to compare the contents of CONST_DOUBLEs or
-	 CONST_INTs because pointer equality is a good enough
-	 comparison for these nodes.  */
+      /* Pointer equality guarantees equality for these nodes.  */
       return 0;
 
     default:
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 1fbd2f3..0c587d1 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -672,20 +672,24 @@ c_getstr (tree src)
   return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
 }
 
-/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
+/* Return a constant integer corresponding to target reading
    GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
 
 static rtx
 c_readstr (const char *str, enum machine_mode mode)
 {
-  HOST_WIDE_INT c[2];
+  wide_int c;
   HOST_WIDE_INT ch;
   unsigned int i, j;
+  HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  unsigned int len = (GET_MODE_PRECISION (mode) + HOST_BITS_PER_WIDE_INT - 1)
+    / HOST_BITS_PER_WIDE_INT;
+
+  for (i = 0; i < len; i++)
+    tmp[i] = 0;
 
   gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
 
-  c[0] = 0;
-  c[1] = 0;
   ch = 1;
   for (i = 0; i < GET_MODE_SIZE (mode); i++)
     {
@@ -696,13 +700,14 @@ c_readstr (const char *str, enum machine_mode mode)
 	  && GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
 	j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
       j *= BITS_PER_UNIT;
-      gcc_assert (j < HOST_BITS_PER_DOUBLE_INT);
 
       if (ch)
 	ch = (unsigned char) str[i];
-      c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
+      tmp[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
     }
-  return immed_double_const (c[0], c[1], mode);
+  
+  c = wide_int::from_array (tmp, len, GET_MODE_PRECISION (mode));
+  return immed_wide_int_const (c, mode);
 }
 
 /* Cast a target constant CST to target CHAR and if that value fits into
@@ -4994,12 +4999,12 @@ expand_builtin_signbit (tree exp, rtx target)
 
   if (bitpos < GET_MODE_BITSIZE (rmode))
     {
-      double_int mask = double_int_zero.set_bit (bitpos);
+      wide_int mask = wide_int::set_bit_in_zero (bitpos, rmode);
 
       if (GET_MODE_SIZE (imode) > GET_MODE_SIZE (rmode))
 	temp = gen_lowpart (rmode, temp);
       temp = expand_binop (rmode, and_optab, temp,
-			   immed_double_int_const (mask, rmode),
+			   immed_wide_int_const (mask, rmode),
 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
   else
diff --git a/gcc/combine.c b/gcc/combine.c
index 6d58b19..bfa151d 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -2669,23 +2669,15 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
 	    offset = -1;
 	}
 
-      if (offset >= 0
-	  && (GET_MODE_PRECISION (GET_MODE (SET_DEST (temp)))
-	      <= HOST_BITS_PER_DOUBLE_INT))
+      if (offset >= 0)
 	{
-	  double_int m, o, i;
+	  wide_int o;
 	  rtx inner = SET_SRC (PATTERN (i3));
 	  rtx outer = SET_SRC (temp);
-
-	  o = rtx_to_double_int (outer);
-	  i = rtx_to_double_int (inner);
-
-	  m = double_int::mask (width);
-	  i &= m;
-	  m = m.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
-	  i = i.llshift (offset, HOST_BITS_PER_DOUBLE_INT);
-	  o = o.and_not (m) | i;
-
+	  
+	  o = (wide_int::from_rtx (outer, GET_MODE (SET_DEST (temp)))
+	       .insert (wide_int::from_rtx (inner, GET_MODE (dest)),
+			offset, width));
 	  combine_merges++;
 	  subst_insn = i3;
 	  subst_low_luid = DF_INSN_LUID (i2);
@@ -2696,8 +2688,8 @@ try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
 	  /* Replace the source in I2 with the new constant and make the
 	     resulting insn the new pattern for I3.  Then skip to where we
 	     validate the pattern.  Everything was set up above.  */
-	  SUBST (SET_SRC (temp),
-		 immed_double_int_const (o, GET_MODE (SET_DEST (temp))));
+	  SUBST (SET_SRC (temp), 
+		 immed_wide_int_const (o, GET_MODE (SET_DEST (temp))));
 
 	  newpat = PATTERN (i2);
 
@@ -5112,7 +5104,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
 		  if (! x)
 		    x = gen_rtx_CLOBBER (mode, const0_rtx);
 		}
-	      else if (CONST_INT_P (new_rtx)
+	      else if (CONST_SCALAR_INT_P (new_rtx)
 		       && GET_CODE (x) == ZERO_EXTEND)
 		{
 		  x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 71d031d..c2b6983 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -55,6 +55,9 @@ typedef const struct rtx_def *const_rtx;
 struct rtvec_def;
 typedef struct rtvec_def *rtvec;
 typedef const struct rtvec_def *const_rtvec;
+struct hwivec_def;
+typedef struct hwivec_def *hwivec;
+typedef const struct hwivec_def *const_hwivec;
 union tree_node;
 typedef union tree_node *tree;
 typedef const union tree_node *const_tree;
diff --git a/gcc/cse.c b/gcc/cse.c
index f2c8f63..8e3bb88 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -2331,15 +2331,23 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
                + (unsigned int) INTVAL (x));
       return hash;
 
+    case CONST_WIDE_INT:
+      {
+	int i;
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hash += CONST_WIDE_INT_ELT (x, i);
+      }
+      return hash;
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
 	 the integers representing the constant.  */
       hash += (unsigned int) code + (unsigned int) GET_MODE (x);
-      if (GET_MODE (x) != VOIDmode)
-	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      else
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	hash += ((unsigned int) CONST_DOUBLE_LOW (x)
 		 + (unsigned int) CONST_DOUBLE_HIGH (x));
+      else
+	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       return hash;
 
     case CONST_FIXED:
@@ -3756,6 +3764,7 @@ equiv_constant (rtx x)
 
       /* See if we previously assigned a constant value to this SUBREG.  */
       if ((new_rtx = lookup_as_function (x, CONST_INT)) != 0
+	  || (new_rtx = lookup_as_function (x, CONST_WIDE_INT)) != 0
           || (new_rtx = lookup_as_function (x, CONST_DOUBLE)) != 0
           || (new_rtx = lookup_as_function (x, CONST_FIXED)) != 0)
         return new_rtx;
diff --git a/gcc/cselib.c b/gcc/cselib.c
index 589e41e..2a3b11d 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -926,8 +926,7 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, enum machine_mode memmode)
   /* These won't be handled correctly by the code below.  */
   switch (GET_CODE (x))
     {
-    case CONST_DOUBLE:
-    case CONST_FIXED:
+    CASE_CONST_UNIQUE:
     case DEBUG_EXPR:
       return 0;
 
@@ -1121,15 +1120,23 @@ cselib_hash_rtx (rtx x, int create, enum machine_mode memmode)
       hash += ((unsigned) CONST_INT << 7) + INTVAL (x);
       return hash ? hash : (unsigned int) CONST_INT;
 
+    case CONST_WIDE_INT:
+      {
+	int i;
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hash += CONST_WIDE_INT_ELT (x, i);
+      }
+      return hash;
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
 	 the integers representing the constant.  */
       hash += (unsigned) code + (unsigned) GET_MODE (x);
-      if (GET_MODE (x) != VOIDmode)
-	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      else
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	hash += ((unsigned) CONST_DOUBLE_LOW (x)
 		 + (unsigned) CONST_DOUBLE_HIGH (x));
+      else
+	hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       return hash ? hash : (unsigned int) CONST_DOUBLE;
 
     case CONST_FIXED:
diff --git a/gcc/defaults.h b/gcc/defaults.h
index 4f43f6f0..0801073 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -1404,6 +1404,14 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define SWITCHABLE_TARGET 0
 #endif
 
+/* If the target supports integers that are wider than two
+   HOST_WIDE_INTs on the host compiler, then the target should define
+   TARGET_SUPPORTS_WIDE_INT and make the appropriate fixups.
+   Otherwise the compiler really is not robust.  */
+#ifndef TARGET_SUPPORTS_WIDE_INT
+#define TARGET_SUPPORTS_WIDE_INT 0
+#endif
+
 #endif /* GCC_INSN_FLAGS_H  */
 
 #endif  /* ! GCC_DEFAULTS_H */
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 8829b0e..2254e2f 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -1525,17 +1525,22 @@ Similarly, there is only one object for the integer whose value is
 
 @findex const_double
 @item (const_double:@var{m} @var{i0} @var{i1} @dots{})
-Represents either a floating-point constant of mode @var{m} or an
-integer constant too large to fit into @code{HOST_BITS_PER_WIDE_INT}
-bits but small enough to fit within twice that number of bits (GCC
-does not provide a mechanism to represent even larger constants).  In
-the latter case, @var{m} will be @code{VOIDmode}.  For integral values
-constants for modes with more bits than twice the number in
-@code{HOST_WIDE_INT} the implied high order bits of that constant are
-copies of the top bit of @code{CONST_DOUBLE_HIGH}.  Note however that
-integral values are neither inherently signed nor inherently unsigned;
-where necessary, signedness is determined by the rtl operation
-instead.
+This represents either a floating-point constant of mode @var{m} or
+(on ports older ports that do not define
+@code{TARGET_SUPPORTS_WIDE_INT}) an integer constant too large to fit
+into @code{HOST_BITS_PER_WIDE_INT} bits but small enough to fit within
+twice that number of bits (GCC does not provide a mechanism to
+represent even larger constants).  In the latter case, @var{m} will be
+@code{VOIDmode}.  For integral values constants for modes with more
+bits than twice the number in @code{HOST_WIDE_INT} the implied high
+order bits of that constant are copies of the top bit of
+@code{CONST_DOUBLE_HIGH}.  Note however that integral values are
+neither inherently signed nor inherently unsigned; where necessary,
+signedness is determined by the rtl operation instead.
+
+On more modern ports, @code{CONST_DOUBLE} only represents floating
+point values.  New ports define to @code{TARGET_SUPPORTS_WIDE_INT} to
+make this designation.
 
 @findex CONST_DOUBLE_LOW
 If @var{m} is @code{VOIDmode}, the bits of the value are stored in
@@ -1550,6 +1555,37 @@ machine's or host machine's floating point format.  To convert them to
 the precise bit pattern used by the target machine, use the macro
 @code{REAL_VALUE_TO_TARGET_DOUBLE} and friends (@pxref{Data Output}).
 
+@findex CONST_WIDE_INT
+@item (const_wide_int:@var{m} @var{nunits} @var{elt0} @dots{})
+This contains an array of @code{HOST_WIDE_INTS} that is large enough
+to hold any constant that can be represented on the target.  This form
+of rtl is only used on targets that define
+@code{TARGET_SUPPORTS_WIDE_INT} to be non zero and then
+@code{CONST_DOUBLES} are only used to hold floating point values.  If
+the target leaves @code{TARGET_SUPPORTS_WIDE_INT} defined as 0,
+@code{CONST_WIDE_INT}s are not used and @code{CONST_DOUBLE}s are as
+they were before.
+
+The values are stored in a compressed format.   The higher order
+0s or -1s are not represented if they are just the logical sign
+extension of the number that is represented.   
+
+@findex CONST_WIDE_INT_VEC
+@item CONST_WIDE_INT_VEC (@var{code})
+Returns the entire array of @code{HOST_WIDE_INT}s that are used to
+store the value.   This macro should be rarely used.
+
+@findex CONST_WIDE_INT_NUNITS
+@item CONST_WIDE_INT_NUNITS (@var{code})
+The number of @code{HOST_WIDE_INT}s used to represent the number.
+Note that this generally be smaller than the number of
+@code{HOST_WIDE_INT}s implied by the mode size.
+
+@findex CONST_WIDE_INT_ELT
+@item CONST_WIDE_INT_NUNITS (@var{code},@var{i})
+Returns the @code{i}th element of the array.   Element 0 is contains
+the low order bits of the constant.
+
 @findex const_fixed
 @item (const_fixed:@var{m} @dots{})
 Represents a fixed-point constant of mode @var{m}.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index ec7ef75..fb06ddd 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11360,3 +11360,50 @@ It returns true if the target supports GNU indirect functions.
 The support includes the assembler, linker and dynamic linker.
 The default value of this hook is based on target's libc.
 @end deftypefn
+
+@defmac TARGET_SUPPORTS_WIDE_INT
+
+On older ports, large integers are stored in @code{CONST_DOUBLE} rtl
+objects.  Newer ports define @code{TARGET_SUPPORTS_WIDE_INT} to be non
+zero to indicate that large integers are stored in
+@code{CONST_WIDE_INT} rtl objects.  The @code{CONST_WIDE_INT} allows
+very large integer constants to be represented.  @code{CONST_DOUBLE}
+are limited to twice the size of host's @code{HOST_WIDE_INT}
+representation.
+
+Converting a port mostly requires looking for the places where
+@code{CONST_DOUBLES} are used with @code{VOIDmode} and replacing that
+code with code that accesses @code{CONST_WIDE_INT}s.  @samp{"grep -i
+const_double"} at the port level gets you to 95% of the changes that
+need to be made.  There are a few places that require a deeper look.
+
+@itemize @bullet
+@item
+There is no equivalent to @code{hval} and @code{lval} for
+@code{CONST_WIDE_INT}s.  This would be difficult to express in the md
+language since there are a variable number of elements.
+
+Most ports only check that @code{hval} is either 0 or -1 to see if the
+value is small.  As mentioned above, this will no longer be necessary
+since small constants are always @code{CONST_INT}.  Of course there
+are still a few exceptions, the alpha's constraint used by the zap
+instruction certainly requires careful examination by C code.
+However, all the current code does is pass the hval and lval to C
+code, so evolving the c code to look at the @code{CONST_WIDE_INT} is
+not really a large change.
+
+@item
+Because there is no standard template that ports use to materialize
+constants, there is likely to be some futzing that is unique to each
+port in this code.
+
+@item
+The rtx costs may have to be adjusted to properly account for larger
+constants that are represented as @code{CONST_WIDE_INT}.
+@end itemize
+
+All and all it does not takes long to convert ports that the
+maintainer is familiar with.
+
+@end defmac
+
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index a418733..105b980 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -11185,3 +11185,50 @@ memory model bits are allowed.
 @hook TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
 
 @hook TARGET_HAS_IFUNC_P
+
+@defmac TARGET_SUPPORTS_WIDE_INT
+
+On older ports, large integers are stored in @code{CONST_DOUBLE} rtl
+objects.  Newer ports define @code{TARGET_SUPPORTS_WIDE_INT} to be non
+zero to indicate that large integers are stored in
+@code{CONST_WIDE_INT} rtl objects.  The @code{CONST_WIDE_INT} allows
+very large integer constants to be represented.  @code{CONST_DOUBLE}
+are limited to twice the size of host's @code{HOST_WIDE_INT}
+representation.
+
+Converting a port mostly requires looking for the places where
+@code{CONST_DOUBLES} are used with @code{VOIDmode} and replacing that
+code with code that accesses @code{CONST_WIDE_INT}s.  @samp{"grep -i
+const_double"} at the port level gets you to 95% of the changes that
+need to be made.  There are a few places that require a deeper look.
+
+@itemize @bullet
+@item
+There is no equivalent to @code{hval} and @code{lval} for
+@code{CONST_WIDE_INT}s.  This would be difficult to express in the md
+language since there are a variable number of elements.
+
+Most ports only check that @code{hval} is either 0 or -1 to see if the
+value is small.  As mentioned above, this will no longer be necessary
+since small constants are always @code{CONST_INT}.  Of course there
+are still a few exceptions, the alpha's constraint used by the zap
+instruction certainly requires careful examination by C code.
+However, all the current code does is pass the hval and lval to C
+code, so evolving the c code to look at the @code{CONST_WIDE_INT} is
+not really a large change.
+
+@item
+Because there is no standard template that ports use to materialize
+constants, there is likely to be some futzing that is unique to each
+port in this code.
+
+@item
+The rtx costs may have to be adjusted to properly account for larger
+constants that are represented as @code{CONST_WIDE_INT}.
+@end itemize
+
+All and all it does not takes long to convert ports that the
+maintainer is familiar with.
+
+@end defmac
+
diff --git a/gcc/dojump.c b/gcc/dojump.c
index 3f04eac..ecbec40 100644
--- a/gcc/dojump.c
+++ b/gcc/dojump.c
@@ -142,6 +142,7 @@ static bool
 prefer_and_bit_test (enum machine_mode mode, int bitnum)
 {
   bool speed_p;
+  wide_int mask = wide_int::set_bit_in_zero (bitnum, mode);
 
   if (and_test == 0)
     {
@@ -162,8 +163,7 @@ prefer_and_bit_test (enum machine_mode mode, int bitnum)
     }
 
   /* Fill in the integers.  */
-  XEXP (and_test, 1)
-    = immed_double_int_const (double_int_zero.set_bit (bitnum), mode);
+  XEXP (and_test, 1) = immed_wide_int_const (mask, mode);
   XEXP (XEXP (shift_test, 0), 1) = GEN_INT (bitnum);
 
   speed_p = optimize_insn_for_speed_p ();
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index de69cc8..5b8088d 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -346,6 +346,17 @@ 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)
 {
@@ -1377,6 +1388,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;
@@ -1633,6 +1647,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 ();
 	  }
@@ -1810,6 +1828,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);
@@ -2019,6 +2051,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 ();
 	  }
@@ -3110,7 +3157,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 *);
 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,
@@ -3735,6 +3782,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
@@ -5299,6 +5361,19 @@ 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;
@@ -5470,6 +5545,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 (at->dw_attr_val.v.val_vec);
       break;
@@ -5740,6 +5818,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 (sizeof (at->dw_attr_val.v.val_vec));
@@ -6204,6 +6288,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)
@@ -7676,6 +7762,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)
@@ -8014,6 +8107,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))
@@ -8453,6 +8560,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;
@@ -11603,9 +11736,8 @@ 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 
+      (wide_int::set_bit_in_zero (GET_MODE_PRECISION (mode) - 1, 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
@@ -12546,7 +12678,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
@@ -12558,13 +12699,27 @@ 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
+	    = wide_int::from_rtx (rtl, mode);
 	}
       break;
 
@@ -13035,7 +13190,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
@@ -13047,12 +13210,27 @@ 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))
+	{
+	  gcc_assert (mode == GET_MODE (rtl) || VOIDmode == GET_MODE (rtl));
+
+	  /* Note that a CONST_DOUBLE rtx could represent either an integer
+	     or a floating-point constant.  A CONST_DOUBLE is used whenever
+	     the constant requires more than one word in order to be
+	     adequately represented.  We output CONST_DOUBLEs as blocks.  */
+	  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
+	    = wide_int::from_rtx (rtl, mode);
 	}
       break;
 
@@ -13068,6 +13246,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))
@@ -13076,15 +13255,8 @@ 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);
-		    }
+		  wide_int val = wide_int::from_rtx (elt, imode);
+		  insert_wide_int (val, p);
 		}
 	      break;
 
@@ -14709,22 +14881,27 @@ 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)
 {
-  unsigned char *p0 = dest;
-  unsigned char *p1 = dest + sizeof (HOST_WIDE_INT);
+  int i;
 
   if (WORDS_BIG_ENDIAN)
-    {
-      p0 = p1;
-      p1 = dest;
-    }
-
-  insert_int ((HOST_WIDE_INT) val.low, sizeof (HOST_WIDE_INT), p0);
-  insert_int ((HOST_WIDE_INT) val.high, sizeof (HOST_WIDE_INT), p1);
+    for (i = (int)get_full_len (val) - 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 < (int)get_full_len (val); 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.  */
@@ -14769,6 +14946,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,
+		   wide_int::from_rtx (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
@@ -14777,7 +14959,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);
@@ -14785,9 +14970,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;
 
@@ -14800,6 +14982,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))
 	  {
@@ -14807,15 +14990,8 @@ 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);
-		  }
+		wide_int val = wide_int::from_rtx (elt, imode);
+		insert_wide_int (val, p);
 	      }
 	    break;
 
@@ -23185,6 +23361,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;
@@ -23274,6 +23453,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 ();
 	  }
@@ -23422,6 +23604,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:
@@ -23465,6 +23649,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 ();
 	}
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index ad03a34..d6af85b 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_DWARF2OUT_H 1
 
 #include "dwarf2.h"	/* ??? Remove this once only used by dwarf2foo.c.  */
+#include "wide-int.h"
 
 typedef struct die_struct *dw_die_ref;
 typedef const struct die_struct *const_dw_die_ref;
@@ -29,6 +30,7 @@ typedef struct dw_val_struct *dw_val_ref;
 typedef struct dw_cfi_struct *dw_cfi_ref;
 typedef struct dw_loc_descr_struct *dw_loc_descr_ref;
 typedef struct dw_loc_list_struct *dw_loc_list_ref;
+typedef struct wide_int *wide_int_ref;
 
 
 /* Call frames are described using a sequence of Call Frame
@@ -139,6 +141,7 @@ enum dw_val_class
   dw_val_class_const,
   dw_val_class_unsigned_const,
   dw_val_class_const_double,
+  dw_val_class_wide_int,
   dw_val_class_vec,
   dw_val_class_flag,
   dw_val_class_die_ref,
@@ -180,6 +183,7 @@ typedef struct GTY(()) dw_val_struct {
       HOST_WIDE_INT GTY ((default)) val_int;
       unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
       double_int GTY ((tag ("dw_val_class_const_double"))) val_double;
+      wide_int_ref GTY ((tag ("dw_val_class_wide_int"))) val_wide;
       dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
       struct dw_val_die_union
 	{
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 538b1ec..747735f 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -124,6 +124,9 @@ rtx cc0_rtx;
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
      htab_t const_int_htab;
 
+static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
+     htab_t const_wide_int_htab;
+
 /* A hash table storing memory attribute structures.  */
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct mem_attrs)))
      htab_t mem_attrs_htab;
@@ -149,6 +152,11 @@ static void set_used_decls (tree);
 static void mark_label_nuses (rtx);
 static hashval_t const_int_htab_hash (const void *);
 static int const_int_htab_eq (const void *, const void *);
+#if TARGET_SUPPORTS_WIDE_INT
+static hashval_t const_wide_int_htab_hash (const void *);
+static int const_wide_int_htab_eq (const void *, const void *);
+static rtx lookup_const_wide_int (rtx);
+#endif
 static hashval_t const_double_htab_hash (const void *);
 static int const_double_htab_eq (const void *, const void *);
 static rtx lookup_const_double (rtx);
@@ -185,6 +193,43 @@ const_int_htab_eq (const void *x, const void *y)
   return (INTVAL ((const_rtx) x) == *((const HOST_WIDE_INT *) y));
 }
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns a hash code for X (which is a really a CONST_WIDE_INT).  */
+
+static hashval_t
+const_wide_int_htab_hash (const void *x)
+{
+  int i;
+  HOST_WIDE_INT hash = 0;
+  const_rtx xr = (const_rtx) x;
+
+  for (i = 0; i < CONST_WIDE_INT_NUNITS (xr); i++)
+    hash += CONST_WIDE_INT_ELT (xr, i);
+
+  return (hashval_t) hash;
+}
+
+/* Returns nonzero if the value represented by X (which is really a
+   CONST_WIDE_INT) is the same as that given by Y (which is really a
+   CONST_WIDE_INT).  */
+
+static int
+const_wide_int_htab_eq (const void *x, const void *y)
+{
+  int i;
+  const_rtx xr = (const_rtx)x;
+  const_rtx yr = (const_rtx)y;
+  if (CONST_WIDE_INT_NUNITS (xr) != CONST_WIDE_INT_NUNITS (yr))
+    return 0;
+
+  for (i = 0; i < CONST_WIDE_INT_NUNITS (xr); i++)
+    if (CONST_WIDE_INT_ELT (xr, i) != CONST_WIDE_INT_ELT (yr, i))
+      return 0;
+  
+  return 1;
+}
+#endif
+
 /* Returns a hash code for X (which is really a CONST_DOUBLE).  */
 static hashval_t
 const_double_htab_hash (const void *x)
@@ -192,7 +237,7 @@ const_double_htab_hash (const void *x)
   const_rtx const value = (const_rtx) x;
   hashval_t h;
 
-  if (GET_MODE (value) == VOIDmode)
+  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (value) == VOIDmode)
     h = CONST_DOUBLE_LOW (value) ^ CONST_DOUBLE_HIGH (value);
   else
     {
@@ -212,7 +257,7 @@ const_double_htab_eq (const void *x, const void *y)
 
   if (GET_MODE (a) != GET_MODE (b))
     return 0;
-  if (GET_MODE (a) == VOIDmode)
+  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (a) == VOIDmode)
     return (CONST_DOUBLE_LOW (a) == CONST_DOUBLE_LOW (b)
 	    && CONST_DOUBLE_HIGH (a) == CONST_DOUBLE_HIGH (b));
   else
@@ -478,6 +523,7 @@ const_fixed_from_fixed_value (FIXED_VALUE_TYPE value, enum machine_mode mode)
   return lookup_const_fixed (fixed);
 }
 
+#if TARGET_SUPPORTS_WIDE_INT == 0
 /* Constructs double_int from rtx CST.  */
 
 double_int
@@ -497,17 +543,60 @@ rtx_to_double_int (const_rtx cst)
   
   return r;
 }
+#endif
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Determine whether WIDE_INT, already exists in the hash table.  If
+   so, return its counterpart; otherwise add it to the hash table and
+   return it.  */
+
+static rtx
+lookup_const_wide_int (rtx wint)
+{
+  void **slot = htab_find_slot (const_wide_int_htab, wint, INSERT);
+  if (*slot == 0)
+    *slot = wint;
 
-/* Return a CONST_DOUBLE or CONST_INT for a value specified as
-   a double_int.  */
+  return (rtx) *slot;
+}
+#endif
 
+/* V contains a wide_int.  A CONST_INT or CONST_WIDE_INT (if
+   TARGET_SUPPORTS_WIDE_INT is defined) or CONST_DOUBLE if
+   TARGET_SUPPORTS_WIDE_INT is not defined is produced based on the
+   number of HOST_WIDE_INTs that are necessary to represent the value
+   in compact form.  */
 rtx
-immed_double_int_const (double_int i, enum machine_mode mode)
+immed_wide_int_const (const wide_int &v, enum machine_mode mode)
 {
-  return immed_double_const (i.low, i.high, mode);
+  unsigned int len = v.get_len ();
+
+  if (len < 2)
+    return gen_int_mode (v.elt (0), mode);
+
+  gcc_assert (GET_MODE_PRECISION (mode) == v.get_precision ());
+
+#if TARGET_SUPPORTS_WIDE_INT
+  {
+    rtx value = const_wide_int_alloc (len);
+    unsigned int i;
+
+    /* It is so tempting to just put the mode in here.  Must control
+       myself ... */
+    PUT_MODE (value, VOIDmode);
+    HWI_PUT_NUM_ELEM (CONST_WIDE_INT_VEC (value), len);
+
+    for (i = 0; i < len; i++)
+      CONST_WIDE_INT_ELT (value, i) = v.elt (i);
+
+    return lookup_const_wide_int (value);
+  }
+#else
+  return immed_double_const (v.elt (0), v.elt (1), mode);
+#endif
 }
 
+#if TARGET_SUPPORTS_WIDE_INT == 0
 /* Return a CONST_DOUBLE or CONST_INT for a value specified as a pair
    of ints: I0 is the low-order word and I1 is the high-order word.
    For values that are larger than HOST_BITS_PER_DOUBLE_INT, the
@@ -559,6 +648,7 @@ immed_double_const (HOST_WIDE_INT i0, HOST_WIDE_INT i1, enum machine_mode mode)
 
   return lookup_const_double (value);
 }
+#endif
 
 rtx
 gen_rtx_REG (enum machine_mode mode, unsigned int regno)
@@ -5694,11 +5784,15 @@ init_emit_once (void)
   enum machine_mode mode;
   enum machine_mode double_mode;
 
-  /* Initialize the CONST_INT, CONST_DOUBLE, CONST_FIXED, and memory attribute
-     hash tables.  */
+  /* Initialize the CONST_INT, CONST_WIDE_INT, CONST_DOUBLE,
+     CONST_FIXED, and memory attribute hash tables.  */
   const_int_htab = htab_create_ggc (37, const_int_htab_hash,
 				    const_int_htab_eq, NULL);
 
+#if TARGET_SUPPORTS_WIDE_INT
+  const_wide_int_htab = htab_create_ggc (37, const_wide_int_htab_hash,
+					 const_wide_int_htab_eq, NULL);
+#endif
   const_double_htab = htab_create_ggc (37, const_double_htab_hash,
 				       const_double_htab_eq, NULL);
 
diff --git a/gcc/explow.c b/gcc/explow.c
index 08a6653..7eebef5 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -95,38 +95,8 @@ plus_constant (enum machine_mode mode, rtx x, HOST_WIDE_INT c)
 
   switch (code)
     {
-    case CONST_INT:
-      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
-	{
-	  double_int di_x = double_int::from_shwi (INTVAL (x));
-	  double_int di_c = double_int::from_shwi (c);
-
-	  bool overflow;
-	  double_int v = di_x.add_with_sign (di_c, false, &overflow);
-	  if (overflow)
-	    gcc_unreachable ();
-
-	  return immed_double_int_const (v, VOIDmode);
-	}
-
-      return GEN_INT (INTVAL (x) + c);
-
-    case CONST_DOUBLE:
-      {
-	double_int di_x = double_int::from_pair (CONST_DOUBLE_HIGH (x),
-						 CONST_DOUBLE_LOW (x));
-	double_int di_c = double_int::from_shwi (c);
-
-	bool overflow;
-	double_int v = di_x.add_with_sign (di_c, false, &overflow);
-	if (overflow)
-	  /* Sorry, we have no way to represent overflows this wide.
-	     To fix, add constant support wider than CONST_DOUBLE.  */
-	  gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT);
-
-	return immed_double_int_const (v, VOIDmode);
-      }
-
+    CASE_CONST_SCALAR_INT:
+      return immed_wide_int_const (wide_int::from_rtx (x, mode) + c, mode);
     case MEM:
       /* If this is a reference to the constant pool, try replacing it with
 	 a reference to a new constant.  If the resulting address isn't
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 3c3a179..ae726c2 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -55,7 +55,6 @@ static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
 static rtx extract_fixed_bit_field (enum machine_mode, rtx,
 				    unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT, rtx, int, bool);
-static rtx mask_rtx (enum machine_mode, int, int, int);
 static rtx lshift_value (enum machine_mode, rtx, int, int);
 static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
 				    unsigned HOST_WIDE_INT, int);
@@ -63,6 +62,18 @@ static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
 static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 
+/* Return a constant integer mask value of mode MODE with BITSIZE ones
+   followed by BITPOS zeros, or the complement of that if COMPLEMENT.
+   The mask is truncated if necessary to the width of mode MODE.  The
+   mask is zero-extended if BITSIZE+BITPOS is too small for MODE.  */
+
+static inline rtx 
+mask_rtx (enum machine_mode mode, int bitpos, int bitsize, bool complement)
+{
+  return immed_wide_int_const 
+    (wide_int::shifted_mask (bitpos, bitsize, complement, mode), mode);
+}
+
 /* Test whether a value is zero of a power of two.  */
 #define EXACT_POWER_OF_2_OR_ZERO_P(x) \
   (((x) & ((x) - (unsigned HOST_WIDE_INT) 1)) == 0)
@@ -1832,39 +1843,15 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
   return expand_shift (RSHIFT_EXPR, mode, op0,
 		       GET_MODE_BITSIZE (mode) - bitsize, target, 0);
 }
-\f
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) mask value
-   of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
-   complement of that if COMPLEMENT.  The mask is truncated if
-   necessary to the width of mode MODE.  The mask is zero-extended if
-   BITSIZE+BITPOS is too small for MODE.  */
-
-static rtx
-mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
-{
-  double_int mask;
-
-  mask = double_int::mask (bitsize);
-  mask = mask.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
-  if (complement)
-    mask = ~mask;
-
-  return immed_double_int_const (mask, mode);
-}
-
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
-   VALUE truncated to BITSIZE bits and then shifted left BITPOS bits.  */
+/* Return a constant integer rtx with the value VALUE truncated to
+   BITSIZE bits and then shifted left BITPOS bits.  */
 
 static rtx
 lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
 {
-  double_int val;
-  
-  val = double_int::from_uhwi (INTVAL (value)).zext (bitsize);
-  val = val.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
-  return immed_double_int_const (val, mode);
+  return 
+    immed_wide_int_const (wide_int::from_rtx (value, mode)
+			  .zext (bitsize).lshift (bitpos), mode);
 }
 \f
 /* Extract a bit field that is split across two words
@@ -3069,37 +3056,41 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 	 only if the constant value exactly fits in an `unsigned int' without
 	 any truncation.  This means that multiplying by negative values does
 	 not work; results are off by 2^32 on a 32 bit machine.  */
-
       if (CONST_INT_P (scalar_op1))
 	{
 	  coeff = INTVAL (scalar_op1);
 	  is_neg = coeff < 0;
 	}
+#if TARGET_SUPPORTS_WIDE_INT
+      else if (CONST_WIDE_INT_P (scalar_op1))
+#else
       else if (CONST_DOUBLE_AS_INT_P (scalar_op1))
+#endif
 	{
-	  /* If we are multiplying in DImode, it may still be a win
-	     to try to work with shifts and adds.  */
-	  if (CONST_DOUBLE_HIGH (scalar_op1) == 0
-	      && (CONST_DOUBLE_LOW (scalar_op1) > 0
-		  || (CONST_DOUBLE_LOW (scalar_op1) < 0
-		      && EXACT_POWER_OF_2_OR_ZERO_P
-			   (CONST_DOUBLE_LOW (scalar_op1)))))
+	  int p = GET_MODE_PRECISION (mode);
+	  wide_int val = wide_int::from_rtx (scalar_op1, mode);
+	  int shift = val.exact_log2 ().to_shwi (); 
+	  /* Perfect power of 2.  */
+	  is_neg = false;
+	  if (shift > 0)
 	    {
-	      coeff = CONST_DOUBLE_LOW (scalar_op1);
-	      is_neg = false;
+	      /* Do the shift count trucation against the bitsize, not
+		 the precision.  See the comment above
+		 wide-int.c:trunc_shift for details.  */
+	      if (SHIFT_COUNT_TRUNCATED)
+		shift &= GET_MODE_BITSIZE (mode) - 1;
+	      /* We could consider adding just a move of 0 to target
+		 if the shift >= p  */
+	      if (shift < p)
+		return expand_shift (LSHIFT_EXPR, mode, op0, 
+				     shift, target, unsignedp);
+	      /* Any positive number that fits in a word.  */
+	      coeff = CONST_WIDE_INT_ELT (scalar_op1, 0);
 	    }
-	  else if (CONST_DOUBLE_LOW (scalar_op1) == 0)
+	  else if (val.sign_mask () == 0)
 	    {
-	      coeff = CONST_DOUBLE_HIGH (scalar_op1);
-	      if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
-		{
-		  int shift = floor_log2 (coeff) + HOST_BITS_PER_WIDE_INT;
-		  if (shift < HOST_BITS_PER_DOUBLE_INT - 1
-		      || mode_bitsize <= HOST_BITS_PER_DOUBLE_INT)
-		    return expand_shift (LSHIFT_EXPR, mode, op0,
-					 shift, target, unsignedp);
-		}
-	      goto skip_synth;
+	      /* Any positive number that fits in a word.  */
+	      coeff = CONST_WIDE_INT_ELT (scalar_op1, 0);
 	    }
 	  else
 	    goto skip_synth;
@@ -3601,9 +3592,10 @@ expmed_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
 static rtx
 expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 {
-  unsigned HOST_WIDE_INT masklow, maskhigh;
   rtx result, temp, shift, label;
   int logd;
+  wide_int mask;
+  int prec = GET_MODE_PRECISION (mode);
 
   logd = floor_log2 (d);
   result = gen_reg_rtx (mode);
@@ -3616,8 +3608,8 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 				      mode, 0, -1);
       if (signmask)
 	{
+	  HOST_WIDE_INT masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
 	  signmask = force_reg (mode, signmask);
-	  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
 	  shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
 
 	  /* Use the rtx_cost of a LSHIFTRT instruction to determine
@@ -3662,19 +3654,11 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
      modulus.  By including the signbit in the operation, many targets
      can avoid an explicit compare operation in the following comparison
      against zero.  */
-
-  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
-  if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
-    {
-      masklow |= (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1);
-      maskhigh = -1;
-    }
-  else
-    maskhigh = (HOST_WIDE_INT) -1
-		 << (GET_MODE_BITSIZE (mode) - HOST_BITS_PER_WIDE_INT - 1);
+  mask = wide_int::mask (logd, false, mode);
+  mask = mask.set_bit (prec - 1);
 
   temp = expand_binop (mode, and_optab, op0,
-		       immed_double_const (masklow, maskhigh, mode),
+		       immed_wide_int_const (mask, mode),
 		       result, 1, OPTAB_LIB_WIDEN);
   if (temp != result)
     emit_move_insn (result, temp);
@@ -3684,10 +3668,10 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 
   temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
 		       0, OPTAB_LIB_WIDEN);
-  masklow = (HOST_WIDE_INT) -1 << logd;
-  maskhigh = -1;
+
+  mask = wide_int::mask (logd, true, mode); 
   temp = expand_binop (mode, ior_optab, temp,
-		       immed_double_const (masklow, maskhigh, mode),
+		       immed_wide_int_const (mask, mode),
 		       result, 1, OPTAB_LIB_WIDEN);
   temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
 		       0, OPTAB_LIB_WIDEN);
@@ -4940,8 +4924,12 @@ make_tree (tree type, rtx x)
 	return t;
       }
 
+    case CONST_WIDE_INT:
+      t = wide_int_to_tree (type, wide_int::from_rtx (x, TYPE_MODE (type)));
+      return t;
+
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
 	t = build_int_cst_wide (type,
 				CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
       else
diff --git a/gcc/expr.c b/gcc/expr.c
index e3fb0b6..9011d46 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -710,23 +710,23 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
   if (mode == oldmode)
     return x;
 
-  /* There is one case that we must handle specially: If we are converting
-     a CONST_INT into a mode whose size is twice HOST_BITS_PER_WIDE_INT and
-     we are to interpret the constant as unsigned, gen_lowpart will do
-     the wrong if the constant appears negative.  What we want to do is
-     make the high-order word of the constant zero, not all ones.  */
+  /* There is one case that we must handle specially: If we are
+     converting a CONST_INT into a mode whose size is larger than
+     HOST_BITS_PER_WIDE_INT and we are to interpret the constant as
+     unsigned, gen_lowpart will do the wrong if the constant appears
+     negative.  What we want to do is make the high-order word of the
+     constant zero, not all ones.  */
 
   if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
-      && GET_MODE_BITSIZE (mode) == HOST_BITS_PER_DOUBLE_INT
+      && GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT
       && CONST_INT_P (x) && INTVAL (x) < 0)
     {
-      double_int val = double_int::from_uhwi (INTVAL (x));
-
+      HOST_WIDE_INT val = INTVAL (x);
       /* We need to zero extend VAL.  */
       if (oldmode != VOIDmode)
-	val = val.zext (GET_MODE_BITSIZE (oldmode));
+	val &= GET_MODE_PRECISION (oldmode) - 1;
 
-      return immed_double_int_const (val, mode);
+      return immed_wide_int_const (wide_int::from_uhwi (val, mode), mode);
     }
 
   /* We can do this with a gen_lowpart if both desired and current modes
@@ -738,7 +738,11 @@ convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
        && GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT)
       || (GET_MODE_CLASS (mode) == MODE_INT
 	  && GET_MODE_CLASS (oldmode) == MODE_INT
-	  && (CONST_DOUBLE_AS_INT_P (x) 
+#if TARGET_SUPPORTS_WIDE_INT
+	  && (CONST_WIDE_INT_P (x)
+#else
+ 	  && (CONST_DOUBLE_AS_INT_P (x)
+#endif
 	      || (GET_MODE_PRECISION (mode) <= GET_MODE_PRECISION (oldmode)
 		  && ((MEM_P (x) && ! MEM_VOLATILE_P (x)
 		       && direct_load[(int) mode])
@@ -1743,6 +1747,7 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
 	    {
 	      rtx first, second;
 
+	      /* TODO: const_wide_int can have sizes other than this...  */
 	      gcc_assert (2 * len == ssize);
 	      split_double (src, &first, &second);
 	      if (i)
@@ -5239,10 +5244,10 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 			       &alt_rtl);
     }
 
-  /* If TEMP is a VOIDmode constant and the mode of the type of EXP is not
-     the same as that of TARGET, adjust the constant.  This is needed, for
-     example, in case it is a CONST_DOUBLE and we want only a word-sized
-     value.  */
+  /* If TEMP is a VOIDmode constant and the mode of the type of EXP is
+     not the same as that of TARGET, adjust the constant.  This is
+     needed, for example, in case it is a CONST_DOUBLE or
+     CONST_WIDE_INT and we want only a word-sized value.  */
   if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode
       && TREE_CODE (exp) != ERROR_MARK
       && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
@@ -7741,11 +7746,12 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
 
   /* All elts simple constants => refer to a constant in memory.  But
      if this is a non-BLKmode mode, let it store a field at a time
-     since that should make a CONST_INT or CONST_DOUBLE when we
-     fold.  Likewise, if we have a target we can use, it is best to
-     store directly into the target unless the type is large enough
-     that memcpy will be used.  If we are making an initializer and
-     all operands are constant, put it in memory as well.
+     since that should make a CONST_INT, CONST_WIDE_INT or
+     CONST_DOUBLE when we fold.  Likewise, if we have a target we can
+     use, it is best to store directly into the target unless the type
+     is large enough that memcpy will be used.  If we are making an
+     initializer and all operands are constant, put it in memory as
+     well.
 
      FIXME: Avoid trying to fill vector constructors piece-meal.
      Output them with output_constant_def below unless we're sure
@@ -8215,17 +8221,18 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 	      && TREE_CONSTANT (treeop1))
 	    {
 	      rtx constant_part;
+	      HOST_WIDE_INT wc;
+	      enum machine_mode wmode = TYPE_MODE (TREE_TYPE (treeop1));
 
 	      op1 = expand_expr (treeop1, subtarget, VOIDmode,
 				 EXPAND_SUM);
-	      /* Use immed_double_const to ensure that the constant is
+	      /* Use wide_int::from_shwi to ensure that the constant is
 		 truncated according to the mode of OP1, then sign extended
 		 to a HOST_WIDE_INT.  Using the constant directly can result
 		 in non-canonical RTL in a 64x32 cross compile.  */
-	      constant_part
-		= immed_double_const (TREE_INT_CST_LOW (treeop0),
-				      (HOST_WIDE_INT) 0,
-				      TYPE_MODE (TREE_TYPE (treeop1)));
+	      wc = TREE_INT_CST_LOW (treeop0);
+	      constant_part 
+		= immed_wide_int_const (wide_int::from_shwi (wc, wmode), wmode);
 	      op1 = plus_constant (mode, op1, INTVAL (constant_part));
 	      if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
 		op1 = force_operand (op1, target);
@@ -8237,7 +8244,8 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 		   && TREE_CONSTANT (treeop0))
 	    {
 	      rtx constant_part;
-
+	      HOST_WIDE_INT wc;
+	      enum machine_mode wmode = TYPE_MODE (TREE_TYPE (treeop0));
 	      op0 = expand_expr (treeop0, subtarget, VOIDmode,
 				 (modifier == EXPAND_INITIALIZER
 				 ? EXPAND_INITIALIZER : EXPAND_SUM));
@@ -8251,14 +8259,13 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 		    return simplify_gen_binary (PLUS, mode, op0, op1);
 		  goto binop2;
 		}
-	      /* Use immed_double_const to ensure that the constant is
+	      /* Use wide_int::from_shwi to ensure that the constant is
 		 truncated according to the mode of OP1, then sign extended
 		 to a HOST_WIDE_INT.  Using the constant directly can result
 		 in non-canonical RTL in a 64x32 cross compile.  */
-	      constant_part
-		= immed_double_const (TREE_INT_CST_LOW (treeop1),
-				      (HOST_WIDE_INT) 0,
-				      TYPE_MODE (TREE_TYPE (treeop0)));
+	      wc = TREE_INT_CST_LOW (treeop1);
+	      constant_part 
+		= immed_wide_int_const (wide_int::from_shwi (wc, wmode), wmode);
 	      op0 = plus_constant (mode, op0, INTVAL (constant_part));
 	      if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
 		op0 = force_operand (op0, target);
@@ -8760,10 +8767,13 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 	 for unsigned bitfield expand this as XOR with a proper constant
 	 instead.  */
       if (reduce_bit_field && TYPE_UNSIGNED (type))
-	temp = expand_binop (mode, xor_optab, op0,
-			     immed_double_int_const
-			       (double_int::mask (TYPE_PRECISION (type)), mode),
-			     target, 1, OPTAB_LIB_WIDEN);
+	{
+	  wide_int mask = wide_int::mask (TYPE_PRECISION (type), false, mode);
+
+	  temp = expand_binop (mode, xor_optab, op0,
+			       immed_wide_int_const (mask, mode),
+			       target, 1, OPTAB_LIB_WIDEN);
+	}
       else
 	temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
       gcc_assert (temp);
@@ -9396,9 +9406,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return decl_rtl;
 
     case INTEGER_CST:
-      temp = immed_double_const (TREE_INT_CST_LOW (exp),
-				 TREE_INT_CST_HIGH (exp), mode);
-
+      temp = immed_wide_int_const (wide_int::from_tree (exp), 
+				   TYPE_MODE (TREE_TYPE (exp)));
       return temp;
 
     case VECTOR_CST:
@@ -9630,8 +9639,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 	op0 = memory_address_addr_space (address_mode, op0, as);
 	if (!integer_zerop (TREE_OPERAND (exp, 1)))
 	  {
-	    rtx off
-	      = immed_double_int_const (mem_ref_offset (exp), address_mode);
+	    wide_int wi = wide_int::from_double_int
+	      (mem_ref_offset (exp), GET_MODE_PRECISION (address_mode));
+	    rtx off = immed_wide_int_const (wi, address_mode);
 	    op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
 	  }
 	op0 = memory_address_addr_space (mode, op0, as);
@@ -10510,9 +10520,10 @@ reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
     }
   else if (TYPE_UNSIGNED (type))
     {
-      rtx mask = immed_double_int_const (double_int::mask (prec),
-					 GET_MODE (exp));
-      return expand_and (GET_MODE (exp), exp, mask, target);
+      enum machine_mode mode = GET_MODE (exp);
+      rtx mask = immed_wide_int_const 
+	(wide_int::mask (prec, false, mode), mode);
+      return expand_and (mode, exp, mask, target);
     }
   else
     {
@@ -11084,8 +11095,9 @@ const_vector_from_tree (tree exp)
 	RTVEC_ELT (v, i) = CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (elt),
 							 inner);
       else
-	RTVEC_ELT (v, i) = immed_double_int_const (tree_to_double_int (elt),
-						   inner);
+	RTVEC_ELT (v, i) 
+	  = immed_wide_int_const (wide_int::from_tree (elt),
+				  TYPE_MODE (TREE_TYPE (elt)));
     }
 
   return gen_rtx_CONST_VECTOR (mode, v);
diff --git a/gcc/final.c b/gcc/final.c
index f6974f4..053aebc 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -3789,8 +3789,16 @@ output_addr_const (FILE *file, rtx x)
       output_addr_const (file, XEXP (x, 0));
       break;
 
+    case CONST_WIDE_INT:
+      /* This should be ok for a while.  */
+      gcc_assert (CONST_WIDE_INT_NUNITS (x) == 2);
+      fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
+	       (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, 1),
+	       (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, 0));
+      break;
+
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
+      if (CONST_DOUBLE_AS_INT_P (x))
 	{
 	  /* We can use %d if the number is one word and positive.  */
 	  if (CONST_DOUBLE_HIGH (x))
diff --git a/gcc/genemit.c b/gcc/genemit.c
index 692ef52..7b1e471 100644
--- a/gcc/genemit.c
+++ b/gcc/genemit.c
@@ -204,6 +204,7 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used)
 
     case CONST_DOUBLE:
     case CONST_FIXED:
+    case CONST_WIDE_INT:
       /* These shouldn't be written in MD files.  Instead, the appropriate
 	 routines in varasm.c should be called.  */
       gcc_unreachable ();
diff --git a/gcc/gengenrtl.c b/gcc/gengenrtl.c
index 5b5a3ca..1f93dd5 100644
--- a/gcc/gengenrtl.c
+++ b/gcc/gengenrtl.c
@@ -142,6 +142,7 @@ static int
 excluded_rtx (int idx)
 {
   return ((strcmp (defs[idx].enumname, "CONST_DOUBLE") == 0)
+	  || (strcmp (defs[idx].enumname, "CONST_WIDE_INT") == 0)
 	  || (strcmp (defs[idx].enumname, "CONST_FIXED") == 0));
 }
 
diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l
index f46cd17..7ece2ab 100644
--- a/gcc/gengtype-lex.l
+++ b/gcc/gengtype-lex.l
@@ -57,7 +57,7 @@ ITYPE	{IWORD}({WS}{IWORD})*
     /* Include '::' in identifiers to capture C++ scope qualifiers.  */
 ID	{CID}({HWS}::{HWS}{CID})*
 EOID	[^[:alnum:]_]
-CXX_KEYWORD inline|public:|private:|protected:|template|operator|friend
+CXX_KEYWORD inline|public:|private:|protected:|template|operator|friend|static
 
 %x in_struct in_struct_comment in_comment
 %option warn noyywrap nounput nodefault perf-report
@@ -110,6 +110,7 @@ CXX_KEYWORD inline|public:|private:|protected:|template|operator|friend
 "const"/{EOID}			/* don't care */
 {CXX_KEYWORD}/{EOID}			|
 "~"					|
+"^"					|
 "&"					{
     *yylval = XDUPVAR (const char, yytext, yyleng, yyleng + 1);
     return IGNORABLE_CXX_KEYWORD;
diff --git a/gcc/gengtype-parse.c b/gcc/gengtype-parse.c
index 68d372e..e1c3c65 100644
--- a/gcc/gengtype-parse.c
+++ b/gcc/gengtype-parse.c
@@ -230,6 +230,12 @@ require_template_declaration (const char *tmpl_name)
   /* Read the comma-separated list of identifiers.  */
   while (token () != '>')
     {
+      if (token () == ENUM)
+	{
+	  advance ();
+	  str = concat (str, "enum ", (char *) 0);
+	  continue;
+	}
       const char *id = require2 (ID, ',');
       if (id == NULL)
 	id = ",";
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index eede798..ca2ee25 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -5442,6 +5442,7 @@ main (int argc, char **argv)
       POS_HERE (do_scalar_typedef ("REAL_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("FIXED_VALUE_TYPE", &pos));
       POS_HERE (do_scalar_typedef ("double_int", &pos));
+      POS_HERE (do_scalar_typedef ("wide_int", &pos));
       POS_HERE (do_scalar_typedef ("uint64_t", &pos));
       POS_HERE (do_scalar_typedef ("uint8", &pos));
       POS_HERE (do_scalar_typedef ("uintptr_t", &pos));
diff --git a/gcc/genpreds.c b/gcc/genpreds.c
index 98488e3..29fafbe 100644
--- a/gcc/genpreds.c
+++ b/gcc/genpreds.c
@@ -612,7 +612,7 @@ write_one_predicate_function (struct pred_data *p)
   add_mode_tests (p);
 
   /* A normal predicate can legitimately not look at enum machine_mode
-     if it accepts only CONST_INTs and/or CONST_DOUBLEs.  */
+     if it accepts only CONST_INTs and/or CONST_WIDE_INT and/or CONST_DOUBLEs.  */
   printf ("int\n%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n{\n",
 	  p->name);
   write_predicate_stmts (p->exp);
@@ -809,8 +809,11 @@ add_constraint (const char *name, const char *regclass,
   if (is_const_int || is_const_dbl)
     {
       enum rtx_code appropriate_code
+#if TARGET_SUPPORTS_WIDE_INT
+	= is_const_int ? CONST_INT : CONST_WIDE_INT;
+#else
 	= is_const_int ? CONST_INT : CONST_DOUBLE;
-
+#endif
       /* Consider relaxing this requirement in the future.  */
       if (regclass
 	  || GET_CODE (exp) != AND
@@ -1075,12 +1078,17 @@ write_tm_constrs_h (void)
 	if (needs_ival)
 	  puts ("  if (CONST_INT_P (op))\n"
 		"    ival = INTVAL (op);");
+#if TARGET_SUPPORTS_WIDE_INT
+	if (needs_lval || needs_hval)
+	  error ("you can't use lval or hval");
+#else
 	if (needs_hval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)"
 		"    hval = CONST_DOUBLE_HIGH (op);");
 	if (needs_lval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode == VOIDmode)"
 		"    lval = CONST_DOUBLE_LOW (op);");
+#endif
 	if (needs_rval)
 	  puts ("  if (GET_CODE (op) == CONST_DOUBLE && mode != VOIDmode)"
 		"    rval = CONST_DOUBLE_REAL_VALUE (op);");
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index 9b9a03e..638e051 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -2775,7 +2775,13 @@ static const struct std_pred_table std_preds[] = {
   {"scratch_operand", false, false, {SCRATCH, REG}},
   {"immediate_operand", false, true, {UNKNOWN}},
   {"const_int_operand", false, false, {CONST_INT}},
+#if TARGET_SUPPORTS_WIDE_INT
+  {"const_wide_int_operand", false, false, {CONST_WIDE_INT}},
+  {"const_scalar_int_operand", false, false, {CONST_INT, CONST_WIDE_INT}},
+  {"const_double_operand", false, false, {CONST_DOUBLE}},
+#else
   {"const_double_operand", false, false, {CONST_INT, CONST_DOUBLE}},
+#endif
   {"nonimmediate_operand", false, false, {SUBREG, REG, MEM}},
   {"nonmemory_operand", false, true, {SUBREG, REG}},
   {"push_operand", false, false, {MEM}},
diff --git a/gcc/optabs.c b/gcc/optabs.c
index a3051ad..3b534b2 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -851,7 +851,8 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
   if (CONSTANT_P (op1) || shift_mask >= BITS_PER_WORD)
     {
       carries = outof_input;
-      tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
+      tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD,
+						       op1_mode), op1_mode);
       tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
 				   0, true, methods);
     }
@@ -866,13 +867,14 @@ expand_subword_shift (enum machine_mode op1_mode, optab binoptab,
 			      outof_input, const1_rtx, 0, unsignedp, methods);
       if (shift_mask == BITS_PER_WORD - 1)
 	{
-	  tmp = immed_double_const (-1, -1, op1_mode);
+	  tmp = immed_wide_int_const (wide_int::minus_one (op1_mode), op1_mode);
 	  tmp = simplify_expand_binop (op1_mode, xor_optab, op1, tmp,
 				       0, true, methods);
 	}
       else
 	{
-	  tmp = immed_double_const (BITS_PER_WORD - 1, 0, op1_mode);
+	  tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD - 1,
+							   op1_mode), op1_mode);
 	  tmp = simplify_expand_binop (op1_mode, sub_optab, tmp, op1,
 				       0, true, methods);
 	}
@@ -1035,7 +1037,8 @@ expand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
      is true when the effective shift value is less than BITS_PER_WORD.
      Set SUPERWORD_OP1 to the shift count that should be used to shift
      OUTOF_INPUT into INTO_TARGET when the condition is false.  */
-  tmp = immed_double_const (BITS_PER_WORD, 0, op1_mode);
+  tmp = immed_wide_int_const (wide_int::from_shwi (BITS_PER_WORD, op1_mode),
+			      op1_mode);
   if (!CONSTANT_P (op1) && shift_mask == BITS_PER_WORD - 1)
     {
       /* Set CMP1 to OP1 & BITS_PER_WORD.  The result is zero iff OP1
@@ -2885,7 +2888,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
   const struct real_format *fmt;
   int bitpos, word, nwords, i;
   enum machine_mode imode;
-  double_int mask;
+  wide_int mask;
   rtx temp, insns;
 
   /* The format has to have a simple sign bit.  */
@@ -2921,7 +2924,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
       nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
     }
 
-  mask = double_int_zero.set_bit (bitpos);
+  mask = wide_int::set_bit_in_zero (bitpos, imode);
   if (code == ABS)
     mask = ~mask;
 
@@ -2943,7 +2946,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
 	    {
 	      temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
 				   op0_piece,
-				   immed_double_int_const (mask, imode),
+				   immed_wide_int_const (mask, imode),
 				   targ_piece, 1, OPTAB_LIB_WIDEN);
 	      if (temp != targ_piece)
 		emit_move_insn (targ_piece, temp);
@@ -2961,7 +2964,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
     {
       temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
 			   gen_lowpart (imode, op0),
-			   immed_double_int_const (mask, imode),
+			   immed_wide_int_const (mask, imode),
 		           gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
       target = lowpart_subreg_maybe_copy (mode, temp, imode);
 
@@ -3560,7 +3563,7 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
     }
   else
     {
-      double_int mask;
+      wide_int mask;
 
       if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
 	{
@@ -3582,10 +3585,9 @@ expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 	  op1 = operand_subword_force (op1, word, mode);
 	}
 
-      mask = double_int_zero.set_bit (bitpos);
-
+      mask = wide_int::set_bit_in_zero (bitpos, imode);
       sign = expand_binop (imode, and_optab, op1,
-			   immed_double_int_const (mask, imode),
+			   immed_wide_int_const (mask, imode),
 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
 
@@ -3629,7 +3631,7 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 		     int bitpos, bool op0_is_abs)
 {
   enum machine_mode imode;
-  double_int mask;
+  wide_int mask, nmask;
   int word, nwords, i;
   rtx temp, insns;
 
@@ -3653,7 +3655,7 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
       nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
     }
 
-  mask = double_int_zero.set_bit (bitpos);
+  mask = wide_int::set_bit_in_zero (bitpos, imode);
 
   if (target == 0
       || target == op0
@@ -3673,14 +3675,16 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
 	  if (i == word)
 	    {
 	      if (!op0_is_abs)
-		op0_piece
-		  = expand_binop (imode, and_optab, op0_piece,
-				  immed_double_int_const (~mask, imode),
-				  NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
+		{
+		  nmask = ~mask;
+  		  op0_piece
+		    = expand_binop (imode, and_optab, op0_piece,
+				    immed_wide_int_const (nmask, imode),
+				    NULL_RTX, 1, OPTAB_LIB_WIDEN);
+		}
 	      op1 = expand_binop (imode, and_optab,
 				  operand_subword_force (op1, i, mode),
-				  immed_double_int_const (mask, imode),
+				  immed_wide_int_const (mask, imode),
 				  NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
 	      temp = expand_binop (imode, ior_optab, op0_piece, op1,
@@ -3700,15 +3704,17 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
   else
     {
       op1 = expand_binop (imode, and_optab, gen_lowpart (imode, op1),
-		          immed_double_int_const (mask, imode),
+		          immed_wide_int_const (mask, imode),
 		          NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
       op0 = gen_lowpart (imode, op0);
       if (!op0_is_abs)
-	op0 = expand_binop (imode, and_optab, op0,
-			    immed_double_int_const (~mask, imode),
-			    NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
+	{
+	  nmask = ~mask;
+	  op0 = expand_binop (imode, and_optab, op0,
+			      immed_wide_int_const (nmask, imode),
+			      NULL_RTX, 1, OPTAB_LIB_WIDEN);
+	}
       temp = expand_binop (imode, ior_optab, op0, op1,
 			   gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
       target = lowpart_subreg_maybe_copy (mode, temp, imode);
diff --git a/gcc/postreload.c b/gcc/postreload.c
index 33462e4..b899fe1 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -295,27 +295,25 @@ reload_cse_simplify_set (rtx set, rtx insn)
 #ifdef LOAD_EXTEND_OP
 	  if (extend_op != UNKNOWN)
 	    {
-	      HOST_WIDE_INT this_val;
+	      wide_int result;
 
-	      /* ??? I'm lazy and don't wish to handle CONST_DOUBLE.  Other
-		 constants, such as SYMBOL_REF, cannot be extended.  */
-	      if (!CONST_INT_P (this_rtx))
+	      if (!CONST_SCALAR_INT_P (this_rtx))
 		continue;
 
-	      this_val = INTVAL (this_rtx);
 	      switch (extend_op)
 		{
 		case ZERO_EXTEND:
-		  this_val &= GET_MODE_MASK (GET_MODE (src));
+		  result = (wide_int::from_rtx (this_rtx, GET_MODE (src))
+			    .zext (word_mode));
 		  break;
 		case SIGN_EXTEND:
-		  /* ??? In theory we're already extended.  */
-		  if (this_val == trunc_int_for_mode (this_val, GET_MODE (src)))
-		    break;
+		  result = (wide_int::from_rtx (this_rtx, GET_MODE (src))
+			    .sext (word_mode));
+		  break;
 		default:
 		  gcc_unreachable ();
 		}
-	      this_rtx = GEN_INT (this_val);
+	      this_rtx = immed_wide_int_const (result, GET_MODE (src));
 	    }
 #endif
 	  this_cost = set_src_cost (this_rtx, speed);
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index d2bda9e..3620bd6 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -612,6 +612,12 @@ print_rtx (const_rtx in_rtx)
 	  fprintf (outfile, " [%s]", s);
 	}
       break;
+
+    case CONST_WIDE_INT:
+      if (! flag_simple)
+	fprintf (outfile, " ");
+      hwivec_output_hex (outfile, CONST_WIDE_INT_VEC (in_rtx));
+      break;
 #endif
 
     case CODE_LABEL:
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index cd58b1f..a73a41b 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -806,6 +806,29 @@ validate_const_int (const char *string)
     fatal_with_file_and_line ("invalid decimal constant \"%s\"\n", string);
 }
 
+static void
+validate_const_wide_int (const char *string)
+{
+  const char *cp;
+  int valid = 1;
+
+  cp = string;
+  while (*cp && ISSPACE (*cp))
+    cp++;
+  /* Skip the leading 0x.  */
+  if (cp[0] == '0' || cp[1] == 'x')
+    cp += 2;
+  else
+    valid = 0;
+  if (*cp == 0)
+    valid = 0;
+  for (; *cp; cp++)
+    if (! ISXDIGIT (*cp))
+      valid = 0;
+  if (!valid)
+    fatal_with_file_and_line ("invalid hex constant \"%s\"\n", string);
+}
+
 /* Record that PTR uses iterator ITERATOR.  */
 
 static void
@@ -1319,6 +1342,56 @@ read_rtx_code (const char *code_name)
 	gcc_unreachable ();
       }
 
+  if (CONST_WIDE_INT_P (return_rtx))
+    {
+      read_name (&name);
+      validate_const_wide_int (name.string);
+      {
+	hwivec hwiv;
+	const char *s = name.string;
+	int len;
+	int index = 0;
+	int gs = HOST_BITS_PER_WIDE_INT/4;
+	int pos;
+	char * buf = XALLOCAVEC (char, gs + 1);
+	unsigned HOST_WIDE_INT wi;
+	int wlen;
+
+	/* Skip the leading spaces.  */
+	while (*s && ISSPACE (*s))
+	  s++;
+
+	/* Skip the leading 0x.  */
+	gcc_assert (s[0] == '0');
+	gcc_assert (s[1] == 'x');
+	s += 2;
+
+	len = strlen (s);
+	pos = len - gs;
+	wlen = (len + gs - 1) / gs;	/* Number of words needed */
+
+	return_rtx = const_wide_int_alloc (wlen);
+
+	hwiv = CONST_WIDE_INT_VEC (return_rtx);
+	while (pos > 0)
+	  {
+#if HOST_BITS_PER_WIDE_INT == 64
+	    sscanf (s + pos, "%16" HOST_WIDE_INT_PRINT "x", &wi);
+#else
+	    sscanf (s + pos, "%8" HOST_WIDE_INT_PRINT "x", &wi);
+#endif
+	    XHWIVEC_ELT (hwiv, index++) = wi;
+	    pos -= gs;
+	  }
+	strncpy (buf, s, gs - pos);
+	buf [gs - pos] = 0;
+	sscanf (buf, "%" HOST_WIDE_INT_PRINT "x", &wi);
+	XHWIVEC_ELT (hwiv, index++) = wi;
+	/* TODO: After reading, do we want to canonicalize with:
+	   value = lookup_const_wide_int (value); ? */
+      }
+    }
+
   c = read_skip_spaces ();
   /* Syntactic sugar for AND and IOR, allowing Lisp-like
      arbitrary number of arguments for them.  */
diff --git a/gcc/recog.c b/gcc/recog.c
index 75d1113..fc93d1a 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -1145,7 +1145,7 @@ immediate_operand (rtx op, enum machine_mode mode)
 					    : mode, op));
 }
 
-/* Returns 1 if OP is an operand that is a CONST_INT.  */
+/* Returns 1 if OP is an operand that is a CONST_INT of mode MODE.  */
 
 int
 const_int_operand (rtx op, enum machine_mode mode)
@@ -1160,8 +1160,64 @@ const_int_operand (rtx op, enum machine_mode mode)
   return 1;
 }
 
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns 1 if OP is an operand that is a CONST_INT or CONST_WIDE_INT
+   of mode MODE.  */
+int
+const_scalar_int_operand (rtx op, enum machine_mode mode)
+{
+  if (!CONST_SCALAR_INT_P (op))
+    return 0;
+
+  if (CONST_INT_P (op))
+    return const_int_operand (op, mode);
+
+  if (mode != VOIDmode)
+    {
+      int prec = GET_MODE_PRECISION (mode);
+      int bitsize = GET_MODE_BITSIZE (mode);
+      
+      if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
+	return 0;
+      
+      if (prec == bitsize)
+	return 1;
+      else
+	{
+	  /* Multiword partial int.  */
+	  HOST_WIDE_INT x 
+	    = CONST_WIDE_INT_ELT (op, CONST_WIDE_INT_NUNITS (op) - 1);
+	  return (wide_int::sext (x, prec & (HOST_BITS_PER_WIDE_INT - 1))
+		  == x);
+	}
+    }
+  return 1;
+}
+
+/* Returns 1 if OP is an operand that is a CONST_WIDE_INT of mode
+   MODE.  This most likely is not as useful as
+   const_scalar_int_operand, but is here for consistancy.  */
+int
+const_wide_int_operand (rtx op, enum machine_mode mode)
+{
+  if (!CONST_WIDE_INT_P (op))
+    return 0;
+
+  return const_scalar_int_operand (op, mode);
+}
+
 /* Returns 1 if OP is an operand that is a constant integer or constant
-   floating-point number.  */
+   floating-point number of MODE.  */
+
+int
+const_double_operand (rtx op, enum machine_mode mode)
+{
+  return (GET_CODE (op) == CONST_DOUBLE)
+	  && (GET_MODE (op) == mode || mode == VOIDmode);
+}
+#else
+/* Returns 1 if OP is an operand that is a constant integer or constant
+   floating-point number of MODE.  */
 
 int
 const_double_operand (rtx op, enum machine_mode mode)
@@ -1177,8 +1233,9 @@ const_double_operand (rtx op, enum machine_mode mode)
 	  && (mode == VOIDmode || GET_MODE (op) == mode
 	      || GET_MODE (op) == VOIDmode));
 }
-
-/* Return 1 if OP is a general operand that is not an immediate operand.  */
+#endif
+/* Return 1 if OP is a general operand that is not an immediate
+   operand of mode MODE.  */
 
 int
 nonimmediate_operand (rtx op, enum machine_mode mode)
@@ -1186,7 +1243,8 @@ nonimmediate_operand (rtx op, enum machine_mode mode)
   return (general_operand (op, mode) && ! CONSTANT_P (op));
 }
 
-/* Return 1 if OP is a register reference or immediate value of mode MODE.  */
+/* Return 1 if OP is a register reference or immediate value of mode
+   MODE.  */
 
 int
 nonmemory_operand (rtx op, enum machine_mode mode)
diff --git a/gcc/rtl.c b/gcc/rtl.c
index b2d88f7..074e425 100644
--- a/gcc/rtl.c
+++ b/gcc/rtl.c
@@ -109,7 +109,7 @@ const enum rtx_class rtx_class[NUM_RTX_CODE] = {
 const unsigned char rtx_code_size[NUM_RTX_CODE] = {
 #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)				\
   (((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE			\
-    || (ENUM) == CONST_FIXED)						\
+    || (ENUM) == CONST_FIXED || (ENUM) == CONST_WIDE_INT)		\
    ? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT)	\
    : RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (rtunion)),
 
@@ -181,18 +181,24 @@ shallow_copy_rtvec (rtvec vec)
 unsigned int
 rtx_size (const_rtx x)
 {
+  if (CONST_WIDE_INT_P (x))
+    return (RTX_HDR_SIZE
+	    + sizeof (struct hwivec_def)
+	    + ((CONST_WIDE_INT_NUNITS (x) - 1)
+	       * sizeof (HOST_WIDE_INT)));
   if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_HAS_BLOCK_INFO_P (x))
     return RTX_HDR_SIZE + sizeof (struct block_symbol);
   return RTX_CODE_SIZE (GET_CODE (x));
 }
 
-/* Allocate an rtx of code CODE.  The CODE is stored in the rtx;
-   all the rest is initialized to zero.  */
+/* Allocate an rtx of code CODE with EXTRA bytes in it.  The CODE is
+   stored in the rtx; all the rest is initialized to zero.  */
 
 rtx
-rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
+rtx_alloc_stat_v (RTX_CODE code MEM_STAT_DECL, int extra)
 {
-  rtx rt = ggc_alloc_rtx_def_stat (RTX_CODE_SIZE (code) PASS_MEM_STAT);
+  rtx rt = ggc_alloc_rtx_def_stat (RTX_CODE_SIZE (code) + extra
+				   PASS_MEM_STAT);
 
   /* We want to clear everything up to the FLD array.  Normally, this
      is one int, but we don't want to assume that and it isn't very
@@ -210,6 +216,29 @@ rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
   return rt;
 }
 
+/* Allocate an rtx of code CODE.  The CODE is stored in the rtx;
+   all the rest is initialized to zero.  */
+
+rtx
+rtx_alloc_stat (RTX_CODE code MEM_STAT_DECL)
+{
+  return rtx_alloc_stat_v (code PASS_MEM_STAT, 0);
+}
+
+/* Write the wide constant OP0 to OUTFILE.  */
+
+void
+hwivec_output_hex (FILE *outfile, const_hwivec op0)
+{
+  int i = HWI_GET_NUM_ELEM (op0);
+  gcc_assert (i > 0);
+  if (XHWIVEC_ELT (op0, i-1) == 0)
+    fprintf (outfile, "0x");
+  fprintf (outfile, HOST_WIDE_INT_PRINT_HEX, XHWIVEC_ELT (op0, --i));
+  while (--i >= 0)
+    fprintf (outfile, HOST_WIDE_INT_PRINT_PADDED_HEX, XHWIVEC_ELT (op0, i));
+}
+
 \f
 /* Return true if ORIG is a sharable CONST.  */
 
@@ -428,7 +457,6 @@ rtx_equal_p_cb (const_rtx x, const_rtx y, rtx_equal_p_callback_function cb)
 	  if (XWINT (x, i) != XWINT (y, i))
 	    return 0;
 	  break;
-
 	case 'n':
 	case 'i':
 	  if (XINT (x, i) != XINT (y, i))
@@ -646,6 +674,10 @@ iterative_hash_rtx (const_rtx x, hashval_t hash)
       return iterative_hash_object (i, hash);
     case CONST_INT:
       return iterative_hash_object (INTVAL (x), hash);
+    case CONST_WIDE_INT:
+      for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	hash = iterative_hash_object (CONST_WIDE_INT_ELT (x, i), hash);
+      return hash;
     case SYMBOL_REF:
       if (XSTR (x, 0))
 	return iterative_hash (XSTR (x, 0), strlen (XSTR (x, 0)) + 1,
@@ -811,6 +843,16 @@ rtl_check_failed_block_symbol (const char *file, int line, const char *func)
 
 /* XXX Maybe print the vector?  */
 void
+hwivec_check_failed_bounds (const_hwivec r, int n, const char *file, int line,
+			    const char *func)
+{
+  internal_error
+    ("RTL check: access of hwi elt %d of vector with last elt %d in %s, at %s:%d",
+     n, GET_NUM_ELEM (r) - 1, func, trim_filename (file), line);
+}
+
+/* XXX Maybe print the vector?  */
+void
 rtvec_check_failed_bounds (const_rtvec r, int n, const char *file, int line,
 			   const char *func)
 {
diff --git a/gcc/rtl.def b/gcc/rtl.def
index f8aea32..4c5eb00 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -342,6 +342,9 @@ DEF_RTL_EXPR(TRAP_IF, "trap_if", "ee", RTX_EXTRA)
 /* numeric integer constant */
 DEF_RTL_EXPR(CONST_INT, "const_int", "w", RTX_CONST_OBJ)
 
+/* numeric integer constant */
+DEF_RTL_EXPR(CONST_WIDE_INT, "const_wide_int", "", RTX_CONST_OBJ)
+
 /* fixed-point constant */
 DEF_RTL_EXPR(CONST_FIXED, "const_fixed", "www", RTX_CONST_OBJ)
 
diff --git a/gcc/rtl.h b/gcc/rtl.h
index e9013ec..d019d9f 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -249,6 +251,14 @@ struct GTY(()) object_block {
   vec<rtx, va_gc> *anchors;
 };
 
+struct GTY((variable_size)) hwivec_def {
+  int num_elem;		/* number of elements */
+  HOST_WIDE_INT elem[1];
+};
+
+#define HWI_GET_NUM_ELEM(HWIVEC)	((HWIVEC)->num_elem)
+#define HWI_PUT_NUM_ELEM(HWIVEC, NUM)	((HWIVEC)->num_elem = (NUM))
+
 /* RTL expression ("rtx").  */
 
 struct GTY((chain_next ("RTX_NEXT (&%h)"),
@@ -344,6 +354,7 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"),
     struct block_symbol block_sym;
     struct real_value rv;
     struct fixed_value fv;
+    struct hwivec_def hwiv;
   } GTY ((special ("rtx_def"), desc ("GET_CODE (&%0)"))) u;
 };
 
@@ -383,13 +394,13 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"),
    for a variable number of things.  The principle use is inside
    PARALLEL expressions.  */
 
+#define NULL_RTVEC (rtvec) 0
+
 struct GTY((variable_size)) rtvec_def {
   int num_elem;		/* number of elements */
   rtx GTY ((length ("%h.num_elem"))) elem[1];
 };
 
-#define NULL_RTVEC (rtvec) 0
-
 #define GET_NUM_ELEM(RTVEC)		((RTVEC)->num_elem)
 #define PUT_NUM_ELEM(RTVEC, NUM)	((RTVEC)->num_elem = (NUM))
 
@@ -399,12 +410,38 @@ struct GTY((variable_size)) rtvec_def {
 /* Predicate yielding nonzero iff X is an rtx for a memory location.  */
 #define MEM_P(X) (GET_CODE (X) == MEM)
 
+#if TARGET_SUPPORTS_WIDE_INT
+
+/* Match CONST_*s that can represent compile-time constant integers.  */
+#define CASE_CONST_SCALAR_INT \
+   case CONST_INT: \
+   case CONST_WIDE_INT
+
+/* Match CONST_*s for which pointer equality corresponds to value 
+   equality.  */
+#define CASE_CONST_UNIQUE \
+   case CONST_INT: \
+   case CONST_WIDE_INT: \
+   case CONST_DOUBLE: \
+   case CONST_FIXED
+
+/* Match all CONST_* rtxes.  */
+#define CASE_CONST_ANY \
+   case CONST_INT: \
+   case CONST_WIDE_INT: \
+   case CONST_DOUBLE: \
+   case CONST_FIXED: \
+   case CONST_VECTOR
+
+#else
+
 /* Match CONST_*s that can represent compile-time constant integers.  */
 #define CASE_CONST_SCALAR_INT \
    case CONST_INT: \
    case CONST_DOUBLE
 
-/* Match CONST_*s for which pointer equality corresponds to value equality.  */
+/* Match CONST_*s for which pointer equality corresponds to value 
+equality.  */
 #define CASE_CONST_UNIQUE \
    case CONST_INT: \
    case CONST_DOUBLE: \
@@ -416,10 +453,17 @@ struct GTY((variable_size)) rtvec_def {
    case CONST_DOUBLE: \
    case CONST_FIXED: \
    case CONST_VECTOR
+#endif
+
+
+
 
 /* Predicate yielding nonzero iff X is an rtx for a constant integer.  */
 #define CONST_INT_P(X) (GET_CODE (X) == CONST_INT)
 
+/* Predicate yielding nonzero iff X is an rtx for a constant integer.  */
+#define CONST_WIDE_INT_P(X) (GET_CODE (X) == CONST_WIDE_INT)
+
 /* Predicate yielding nonzero iff X is an rtx for a constant fixed-point.  */
 #define CONST_FIXED_P(X) (GET_CODE (X) == CONST_FIXED)
 
@@ -432,8 +476,13 @@ struct GTY((variable_size)) rtvec_def {
   (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == VOIDmode)
 
 /* Predicate yielding true iff X is an rtx for a integer const.  */
+#if TARGET_SUPPORTS_WIDE_INT
+#define CONST_SCALAR_INT_P(X) \
+  (CONST_INT_P (X) || CONST_WIDE_INT_P (X))
+#else
 #define CONST_SCALAR_INT_P(X) \
   (CONST_INT_P (X) || CONST_DOUBLE_AS_INT_P (X))
+#endif
 
 /* Predicate yielding true iff X is an rtx for a double-int.  */
 #define CONST_DOUBLE_AS_FLOAT_P(X) \
@@ -594,6 +643,13 @@ struct GTY((variable_size)) rtvec_def {
 			       __FUNCTION__);				\
      &_rtx->u.hwint[_n]; }))
 
+#define XHWIVEC_ELT(HWIVEC, I) __extension__				\
+(*({ __typeof (HWIVEC) const _hwivec = (HWIVEC); const int _i = (I);	\
+     if (_i < 0 || _i >= HWI_GET_NUM_ELEM (_hwivec))			\
+       hwivec_check_failed_bounds (_hwivec, _i, __FILE__, __LINE__,	\
+				  __FUNCTION__);			\
+     &_hwivec->elem[_i]; }))
+
 #define XCWINT(RTX, N, C) __extension__					\
 (*({ __typeof (RTX) const _rtx = (RTX);					\
      if (GET_CODE (_rtx) != (C))					\
@@ -630,6 +686,11 @@ struct GTY((variable_size)) rtvec_def {
 				    __FUNCTION__);			\
    &_symbol->u.block_sym; })
 
+#define HWIVEC_CHECK(RTX,C) __extension__				\
+({ __typeof (RTX) const _symbol = (RTX);				\
+   RTL_CHECKC1 (_symbol, 0, C);						\
+   &_symbol->u.hwiv; })
+
 extern void rtl_check_failed_bounds (const_rtx, int, const char *, int,
 				     const char *)
     ATTRIBUTE_NORETURN;
@@ -650,6 +711,9 @@ extern void rtl_check_failed_code_mode (const_rtx, enum rtx_code, enum machine_m
     ATTRIBUTE_NORETURN;
 extern void rtl_check_failed_block_symbol (const char *, int, const char *)
     ATTRIBUTE_NORETURN;
+extern void hwivec_check_failed_bounds (const_rtvec, int, const char *, int,
+					const char *)
+    ATTRIBUTE_NORETURN;
 extern void rtvec_check_failed_bounds (const_rtvec, int, const char *, int,
 				       const char *)
     ATTRIBUTE_NORETURN;
@@ -662,12 +726,14 @@ extern void rtvec_check_failed_bounds (const_rtvec, int, const char *, int,
 #define RTL_CHECKC2(RTX, N, C1, C2) ((RTX)->u.fld[N])
 #define RTVEC_ELT(RTVEC, I)	    ((RTVEC)->elem[I])
 #define XWINT(RTX, N)		    ((RTX)->u.hwint[N])
+#define XHWIVEC_ELT(HWIVEC, I)	    ((HWIVEC)->elem[I])
 #define XCWINT(RTX, N, C)	    ((RTX)->u.hwint[N])
 #define XCMWINT(RTX, N, C, M)	    ((RTX)->u.hwint[N])
 #define XCNMWINT(RTX, N, C, M)	    ((RTX)->u.hwint[N])
 #define XCNMPRV(RTX, C, M)	    (&(RTX)->u.rv)
 #define XCNMPFV(RTX, C, M)	    (&(RTX)->u.fv)
 #define BLOCK_SYMBOL_CHECK(RTX)	    (&(RTX)->u.block_sym)
+#define HWIVEC_CHECK(RTX,C)	    (&(RTX)->u.hwiv)
 
 #endif
 
@@ -810,8 +876,8 @@ extern void rtl_check_failed_flag (const char *, const_rtx, const char *,
 #define XCCFI(RTX, N, C)      (RTL_CHECKC1 (RTX, N, C).rt_cfi)
 #define XCCSELIB(RTX, N, C)   (RTL_CHECKC1 (RTX, N, C).rt_cselib)
 
-#define XCVECEXP(RTX, N, M, C)	RTVEC_ELT (XCVEC (RTX, N, C), M)
-#define XCVECLEN(RTX, N, C)	GET_NUM_ELEM (XCVEC (RTX, N, C))
+#define XCVECEXP(RTX, N, M, C) RTVEC_ELT (XCVEC (RTX, N, C), M)
+#define XCVECLEN(RTX, N, C)    GET_NUM_ELEM (XCVEC (RTX, N, C))
 
 #define XC2EXP(RTX, N, C1, C2)      (RTL_CHECKC2 (RTX, N, C1, C2).rt_rtx)
 \f
@@ -1152,9 +1218,19 @@ rhs_regno (const_rtx x)
 #define INTVAL(RTX) XCWINT(RTX, 0, CONST_INT)
 #define UINTVAL(RTX) ((unsigned HOST_WIDE_INT) INTVAL (RTX))
 
+/* For a CONST_WIDE_INT, CONST_WIDE_INT_NUNITS is the number of
+   elements actually needed to represent the constant.
+   CONST_WIDE_INT_ELT gets one of the elements.  0 is the least
+   significant HOST_WIDE_INT.  */
+#define CONST_WIDE_INT_VEC(RTX) HWIVEC_CHECK (RTX, CONST_WIDE_INT)
+#define CONST_WIDE_INT_NUNITS(RTX) HWI_GET_NUM_ELEM (CONST_WIDE_INT_VEC (RTX))
+#define CONST_WIDE_INT_ELT(RTX, N) XHWIVEC_ELT (CONST_WIDE_INT_VEC (RTX), N) 
+
 /* For a CONST_DOUBLE:
+#if TARGET_SUPPORTS_WIDE_INT == 0
    For a VOIDmode, there are two integers CONST_DOUBLE_LOW is the
      low-order word and ..._HIGH the high-order.
+#endif
    For a float, there is a REAL_VALUE_TYPE structure, and
      CONST_DOUBLE_REAL_VALUE(r) is a pointer to it.  */
 #define CONST_DOUBLE_LOW(r) XCMWINT (r, 0, CONST_DOUBLE, VOIDmode)
@@ -1764,6 +1889,12 @@ extern rtx plus_constant (enum machine_mode, rtx, HOST_WIDE_INT);
 /* In rtl.c */
 extern rtx rtx_alloc_stat (RTX_CODE MEM_STAT_DECL);
 #define rtx_alloc(c) rtx_alloc_stat (c MEM_STAT_INFO)
+extern rtx rtx_alloc_stat_v (RTX_CODE MEM_STAT_DECL, int);
+#define rtx_alloc_v(c, SZ) rtx_alloc_stat_v (c MEM_STAT_INFO, SZ)
+#define const_wide_int_alloc(NWORDS)				\
+  rtx_alloc_v (CONST_WIDE_INT,					\
+	       (sizeof (struct hwivec_def)			\
+		+ ((NWORDS)-1) * sizeof (HOST_WIDE_INT)))	\
 
 extern rtvec rtvec_alloc (int);
 extern rtvec shallow_copy_rtvec (rtvec);
@@ -1820,10 +1951,17 @@ extern void start_sequence (void);
 extern void push_to_sequence (rtx);
 extern void push_to_sequence2 (rtx, rtx);
 extern void end_sequence (void);
+#if TARGET_SUPPORTS_WIDE_INT == 0
 extern double_int rtx_to_double_int (const_rtx);
-extern rtx immed_double_int_const (double_int, enum machine_mode);
+#endif
+extern void hwivec_output_hex (FILE *, const_hwivec);
+#ifndef GENERATOR_FILE
+extern rtx immed_wide_int_const (const wide_int &cst, enum machine_mode mode);
+#endif
+#if TARGET_SUPPORTS_WIDE_INT == 0
 extern rtx immed_double_const (HOST_WIDE_INT, HOST_WIDE_INT,
 			       enum machine_mode);
+#endif
 
 /* In loop-iv.c  */
 
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index b198685..0fe1d0e 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -3091,6 +3091,8 @@ commutative_operand_precedence (rtx op)
   /* Constants always come the second operand.  Prefer "nice" constants.  */
   if (code == CONST_INT)
     return -8;
+  if (code == CONST_WIDE_INT)
+    return -8;
   if (code == CONST_DOUBLE)
     return -7;
   if (code == CONST_FIXED)
@@ -3103,6 +3105,8 @@ commutative_operand_precedence (rtx op)
     case RTX_CONST_OBJ:
       if (code == CONST_INT)
         return -6;
+      if (code == CONST_WIDE_INT)
+        return -6;
       if (code == CONST_DOUBLE)
         return -5;
       if (code == CONST_FIXED)
@@ -5289,7 +5293,10 @@ get_address_mode (rtx mem)
 /* Split up a CONST_DOUBLE or integer constant rtx
    into two rtx's for single words,
    storing in *FIRST the word that comes first in memory in the target
-   and in *SECOND the other.  */
+   and in *SECOND the other. 
+
+   TODO: This function needs to be rewritten to work on any size
+   integer.  */
 
 void
 split_double (rtx value, rtx *first, rtx *second)
@@ -5366,6 +5373,22 @@ split_double (rtx value, rtx *first, rtx *second)
 	    }
 	}
     }
+  else if (GET_CODE (value) == CONST_WIDE_INT)
+    {
+      /* All of this is scary code and needs to be converted to
+	 properly work with any size integer.  */
+      gcc_assert (CONST_WIDE_INT_NUNITS (value) == 2);
+      if (WORDS_BIG_ENDIAN)
+	{
+	  *first = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+	  *second = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+	}
+      else
+	{
+	  *first = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
+	  *second = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
+	}
+    }
   else if (!CONST_DOUBLE_P (value))
     {
       if (WORDS_BIG_ENDIAN)
diff --git a/gcc/sched-vis.c b/gcc/sched-vis.c
index 763230c..979aab1 100644
--- a/gcc/sched-vis.c
+++ b/gcc/sched-vis.c
@@ -432,6 +432,23 @@ print_value (pretty_printer *pp, const_rtx x, int verbose)
       pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
 		 (unsigned HOST_WIDE_INT) INTVAL (x));
       break;
+
+    case CONST_WIDE_INT:
+      {
+	const char *sep = "<";
+	int i;
+	for (i = CONST_WIDE_INT_NUNITS (x) - 1; i >= 0; i--)
+	  {
+	    pp_string (pp, sep);
+	    sep = ",";
+	    sprintf (tmp, HOST_WIDE_INT_PRINT_HEX,
+		     (unsigned HOST_WIDE_INT) CONST_WIDE_INT_ELT (x, i));
+	    pp_string (pp, tmp);
+	  }
+        pp_greater (pp);
+      }
+      break;
+
     case CONST_DOUBLE:
       if (FLOAT_MODE_P (GET_MODE (x)))
 	{
diff --git a/gcc/sel-sched-ir.c b/gcc/sel-sched-ir.c
index 47e7695..828cac3 100644
--- a/gcc/sel-sched-ir.c
+++ b/gcc/sel-sched-ir.c
@@ -1141,10 +1141,10 @@ lhs_and_rhs_separable_p (rtx lhs, rtx rhs)
   if (lhs == NULL || rhs == NULL)
     return false;
 
-  /* Do not schedule CONST, CONST_INT and CONST_DOUBLE etc as rhs: no point
-     to use reg, if const can be used.  Moreover, scheduling const as rhs may
-     lead to mode mismatch cause consts don't have modes but they could be
-     merged from branches where the same const used in different modes.  */
+  /* Do not schedule constants as rhs: no point to use reg, if const
+     can be used.  Moreover, scheduling const as rhs may lead to mode
+     mismatch cause consts don't have modes but they could be merged
+     from branches where the same const used in different modes.  */
   if (CONSTANT_P (rhs))
     return false;
 
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 791f91a..8c7c9a4 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -86,6 +86,22 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
   if (width <= HOST_BITS_PER_WIDE_INT
       && CONST_INT_P (x))
     val = INTVAL (x);
+#if TARGET_SUPPORTS_WIDE_INT
+  else if (CONST_WIDE_INT_P (x))
+    {
+      unsigned int i;
+      unsigned int elts = CONST_WIDE_INT_NUNITS (x);
+      if (elts != (width + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+	return false;
+      for (i = 0; i < elts - 1; i++)
+	if (CONST_WIDE_INT_ELT (x, i) != 0)
+	  return false;
+      val = CONST_WIDE_INT_ELT (x, elts - 1);
+      width %= HOST_BITS_PER_WIDE_INT;
+      if (width == 0)
+	width = HOST_BITS_PER_WIDE_INT;
+    }
+#else
   else if (width <= HOST_BITS_PER_DOUBLE_INT
 	   && CONST_DOUBLE_AS_INT_P (x)
 	   && CONST_DOUBLE_LOW (x) == 0)
@@ -93,8 +109,9 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
       val = CONST_DOUBLE_HIGH (x);
       width -= HOST_BITS_PER_WIDE_INT;
     }
+#endif
   else
-    /* FIXME: We don't yet have a representation for wider modes.  */
+    /* X is not an integer constant.  */
     return false;
 
   if (width < HOST_BITS_PER_WIDE_INT)
@@ -1496,7 +1513,6 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 				rtx op, enum machine_mode op_mode)
 {
   unsigned int width = GET_MODE_PRECISION (mode);
-  unsigned int op_width = GET_MODE_PRECISION (op_mode);
 
   if (code == VEC_DUPLICATE)
     {
@@ -1570,8 +1586,19 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       if (CONST_INT_P (op))
 	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
       else
+#if TARGET_SUPPORTS_WIDE_INT
+	{
+	  /* The conversion code to floats really want exactly 2 HWIs.
+	     This needs to be fixed.  For now, if the constant is
+	     really big, just return 0 which is safe.  */
+	  if (CONST_WIDE_INT_NUNITS (op) > 2)
+	    return 0;
+	  lv = CONST_WIDE_INT_ELT (op, 0);
+	  hv = CONST_WIDE_INT_ELT (op, 1);
+	}
+#else
 	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
-
+#endif
       REAL_VALUE_FROM_INT (d, lv, hv, mode);
       d = real_value_truncate (mode, d);
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
@@ -1584,8 +1611,19 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       if (CONST_INT_P (op))
 	lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
       else
+#if TARGET_SUPPORTS_WIDE_INT
+	{
+	  /* The conversion code to floats really want exactly 2 HWIs.
+	     This needs to be fixed.  For now, if the constant is
+	     really big, just return 0 which is safe.  */
+	  if (CONST_WIDE_INT_NUNITS (op) > 2)
+	    return 0;
+	  lv = CONST_WIDE_INT_ELT (op, 0);
+	  hv = CONST_WIDE_INT_ELT (op, 1);
+	}
+#else
 	lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
-
+#endif
       if (op_mode == VOIDmode
 	  || GET_MODE_PRECISION (op_mode) > HOST_BITS_PER_DOUBLE_INT)
 	/* We should never get a negative number.  */
@@ -1598,302 +1636,82 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
 
-  if (CONST_INT_P (op)
-      && width <= HOST_BITS_PER_WIDE_INT && width > 0)
+  if (CONST_SCALAR_INT_P (op) && width > 0)
     {
-      HOST_WIDE_INT arg0 = INTVAL (op);
-      HOST_WIDE_INT val;
+      wide_int result;
+      enum machine_mode imode = op_mode == VOIDmode ? mode : op_mode;
+      wide_int op0 = wide_int::from_rtx (op, imode);
+
+#if TARGET_SUPPORTS_WIDE_INT == 0
+      /* This assert keeps the simplification from producing a result
+	 that cannot be represented in a CONST_DOUBLE but a lot of
+	 upstream callers expect that this function never fails to
+	 simplify something and so you if you added this to the test
+	 above the code would die later anyway.  If this assert
+	 happens, you just need to make the port support wide int.  */
+      gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT); 
+#endif
 
       switch (code)
 	{
 	case NOT:
-	  val = ~ arg0;
+	  result = ~op0;
 	  break;
 
 	case NEG:
-	  val = - arg0;
+	  result = op0.neg ();
 	  break;
 
 	case ABS:
-	  val = (arg0 >= 0 ? arg0 : - arg0);
+	  result = op0.abs ();
 	  break;
 
 	case FFS:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = ffs_hwi (arg0);
+	  result = op0.ffs ();
 	  break;
 
 	case CLZ:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0 && CLZ_DEFINED_VALUE_AT_ZERO (mode, val))
-	    ;
-	  else
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 1;
+	  result = op0.clz ();
 	  break;
 
 	case CLRSB:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0)
-	    val = GET_MODE_PRECISION (mode) - 1;
-	  else if (arg0 >= 0)
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 2;
-	  else if (arg0 < 0)
-	    val = GET_MODE_PRECISION (mode) - floor_log2 (~arg0) - 2;
+	  result = op0.clrsb ();
 	  break;
-
+	  
 	case CTZ:
-	  arg0 &= GET_MODE_MASK (mode);
-	  if (arg0 == 0)
-	    {
-	      /* Even if the value at zero is undefined, we have to come
-		 up with some replacement.  Seems good enough.  */
-	      if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, val))
-		val = GET_MODE_PRECISION (mode);
-	    }
-	  else
-	    val = ctz_hwi (arg0);
+	  result = op0.ctz ();
 	  break;
 
 	case POPCOUNT:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = 0;
-	  while (arg0)
-	    val++, arg0 &= arg0 - 1;
+	  result = op0.popcount ();
 	  break;
 
 	case PARITY:
-	  arg0 &= GET_MODE_MASK (mode);
-	  val = 0;
-	  while (arg0)
-	    val++, arg0 &= arg0 - 1;
-	  val &= 1;
+	  result = op0.parity ();
 	  break;
 
 	case BSWAP:
-	  {
-	    unsigned int s;
-
-	    val = 0;
-	    for (s = 0; s < width; s += 8)
-	      {
-		unsigned int d = width - s - 8;
-		unsigned HOST_WIDE_INT byte;
-		byte = (arg0 >> s) & 0xff;
-		val |= byte << d;
-	      }
-	  }
+	  result = op0.bswap ();
 	  break;
 
 	case TRUNCATE:
-	  val = arg0;
+	  result = op0.zforce_to_size (width);
 	  break;
 
 	case ZERO_EXTEND:
-	  /* When zero-extending a CONST_INT, we need to know its
-             original mode.  */
-	  gcc_assert (op_mode != VOIDmode);
-	  if (op_width == HOST_BITS_PER_WIDE_INT)
-	    {
-	      /* If we were really extending the mode,
-		 we would have to distinguish between zero-extension
-		 and sign-extension.  */
-	      gcc_assert (width == op_width);
-	      val = arg0;
-	    }
-	  else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
-	    val = arg0 & GET_MODE_MASK (op_mode);
-	  else
-	    return 0;
+	  result = op0.zforce_to_size (width);
 	  break;
 
 	case SIGN_EXTEND:
-	  if (op_mode == VOIDmode)
-	    op_mode = mode;
-	  op_width = GET_MODE_PRECISION (op_mode);
-	  if (op_width == HOST_BITS_PER_WIDE_INT)
-	    {
-	      /* If we were really extending the mode,
-		 we would have to distinguish between zero-extension
-		 and sign-extension.  */
-	      gcc_assert (width == op_width);
-	      val = arg0;
-	    }
-	  else if (op_width < HOST_BITS_PER_WIDE_INT)
-	    {
-	      val = arg0 & GET_MODE_MASK (op_mode);
-	      if (val_signbit_known_set_p (op_mode, val))
-		val |= ~GET_MODE_MASK (op_mode);
-	    }
-	  else
-	    return 0;
+	  result = op0.sforce_to_size (width);
 	  break;
 
 	case SQRT:
-	case FLOAT_EXTEND:
-	case FLOAT_TRUNCATE:
-	case SS_TRUNCATE:
-	case US_TRUNCATE:
-	case SS_NEG:
-	case US_NEG:
-	case SS_ABS:
-	  return 0;
-
-	default:
-	  gcc_unreachable ();
-	}
-
-      return gen_int_mode (val, mode);
-    }
-
-  /* We can do some operations on integer CONST_DOUBLEs.  Also allow
-     for a DImode operation on a CONST_INT.  */
-  else if (width <= HOST_BITS_PER_DOUBLE_INT
-	   && (CONST_DOUBLE_AS_INT_P (op) || CONST_INT_P (op)))
-    {
-      double_int first, value;
-
-      if (CONST_DOUBLE_AS_INT_P (op))
-	first = double_int::from_pair (CONST_DOUBLE_HIGH (op),
-				       CONST_DOUBLE_LOW (op));
-      else
-	first = double_int::from_shwi (INTVAL (op));
-
-      switch (code)
-	{
-	case NOT:
-	  value = ~first;
-	  break;
-
-	case NEG:
-	  value = -first;
-	  break;
-
-	case ABS:
-	  if (first.is_negative ())
-	    value = -first;
-	  else
-	    value = first;
-	  break;
-
-	case FFS:
-	  value.high = 0;
-	  if (first.low != 0)
-	    value.low = ffs_hwi (first.low);
-	  else if (first.high != 0)
-	    value.low = HOST_BITS_PER_WIDE_INT + ffs_hwi (first.high);
-	  else
-	    value.low = 0;
-	  break;
-
-	case CLZ:
-	  value.high = 0;
-	  if (first.high != 0)
-	    value.low = GET_MODE_PRECISION (mode) - floor_log2 (first.high) - 1
-	              - HOST_BITS_PER_WIDE_INT;
-	  else if (first.low != 0)
-	    value.low = GET_MODE_PRECISION (mode) - floor_log2 (first.low) - 1;
-	  else if (! CLZ_DEFINED_VALUE_AT_ZERO (mode, value.low))
-	    value.low = GET_MODE_PRECISION (mode);
-	  break;
-
-	case CTZ:
-	  value.high = 0;
-	  if (first.low != 0)
-	    value.low = ctz_hwi (first.low);
-	  else if (first.high != 0)
-	    value.low = HOST_BITS_PER_WIDE_INT + ctz_hwi (first.high);
-	  else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, value.low))
-	    value.low = GET_MODE_PRECISION (mode);
-	  break;
-
-	case POPCOUNT:
-	  value = double_int_zero;
-	  while (first.low)
-	    {
-	      value.low++;
-	      first.low &= first.low - 1;
-	    }
-	  while (first.high)
-	    {
-	      value.low++;
-	      first.high &= first.high - 1;
-	    }
-	  break;
-
-	case PARITY:
-	  value = double_int_zero;
-	  while (first.low)
-	    {
-	      value.low++;
-	      first.low &= first.low - 1;
-	    }
-	  while (first.high)
-	    {
-	      value.low++;
-	      first.high &= first.high - 1;
-	    }
-	  value.low &= 1;
-	  break;
-
-	case BSWAP:
-	  {
-	    unsigned int s;
-
-	    value = double_int_zero;
-	    for (s = 0; s < width; s += 8)
-	      {
-		unsigned int d = width - s - 8;
-		unsigned HOST_WIDE_INT byte;
-
-		if (s < HOST_BITS_PER_WIDE_INT)
-		  byte = (first.low >> s) & 0xff;
-		else
-		  byte = (first.high >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff;
-
-		if (d < HOST_BITS_PER_WIDE_INT)
-		  value.low |= byte << d;
-		else
-		  value.high |= byte << (d - HOST_BITS_PER_WIDE_INT);
-	      }
-	  }
-	  break;
-
-	case TRUNCATE:
-	  /* This is just a change-of-mode, so do nothing.  */
-	  value = first;
-	  break;
-
-	case ZERO_EXTEND:
-	  gcc_assert (op_mode != VOIDmode);
-
-	  if (op_width > HOST_BITS_PER_WIDE_INT)
-	    return 0;
-
-	  value = double_int::from_uhwi (first.low & GET_MODE_MASK (op_mode));
-	  break;
-
-	case SIGN_EXTEND:
-	  if (op_mode == VOIDmode
-	      || op_width > HOST_BITS_PER_WIDE_INT)
-	    return 0;
-	  else
-	    {
-	      value.low = first.low & GET_MODE_MASK (op_mode);
-	      if (val_signbit_known_set_p (op_mode, value.low))
-		value.low |= ~GET_MODE_MASK (op_mode);
-
-	      value.high = HWI_SIGN_EXTEND (value.low);
-	    }
-	  break;
-
-	case SQRT:
-	  return 0;
-
 	default:
 	  return 0;
 	}
 
-      return immed_double_int_const (value, mode);
+      return immed_wide_int_const (result, mode);
     }
 
   else if (CONST_DOUBLE_AS_FLOAT_P (op) 
@@ -1945,7 +1763,6 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	}
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
-
   else if (CONST_DOUBLE_AS_FLOAT_P (op)
 	   && SCALAR_FLOAT_MODE_P (GET_MODE (op))
 	   && GET_MODE_CLASS (mode) == MODE_INT
@@ -1958,9 +1775,12 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 
       /* This was formerly used only for non-IEEE float.
 	 eggert@twinsun.com says it is safe for IEEE also.  */
-      HOST_WIDE_INT xh, xl, th, tl;
+      HOST_WIDE_INT th, tl;
       REAL_VALUE_TYPE x, t;
+      wide_int wc;
       REAL_VALUE_FROM_CONST_DOUBLE (x, op);
+      HOST_WIDE_INT tmp[2];
+
       switch (code)
 	{
 	case FIX:
@@ -1982,8 +1802,8 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  real_from_integer (&t, VOIDmode, tl, th, 0);
 	  if (REAL_VALUES_LESS (t, x))
 	    {
-	      xh = th;
-	      xl = tl;
+	      tmp[1] = th;
+	      tmp[0] = tl;
 	      break;
 	    }
 
@@ -2002,11 +1822,11 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  real_from_integer (&t, VOIDmode, tl, th, 0);
 	  if (REAL_VALUES_LESS (x, t))
 	    {
-	      xh = th;
-	      xl = tl;
+	      tmp[1] = th;
+	      tmp[0] = tl;
 	      break;
 	    }
-	  REAL_VALUE_TO_INT (&xl, &xh, x);
+	  REAL_VALUE_TO_INT (&tmp[0], &tmp[1], x);
 	  break;
 
 	case UNSIGNED_FIX:
@@ -2033,18 +1853,19 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  real_from_integer (&t, VOIDmode, tl, th, 1);
 	  if (REAL_VALUES_LESS (t, x))
 	    {
-	      xh = th;
-	      xl = tl;
+	      tmp[1] = th;
+	      tmp[0] = tl;
 	      break;
 	    }
 
-	  REAL_VALUE_TO_INT (&xl, &xh, x);
+	  REAL_VALUE_TO_INT (&tmp[0], &tmp[1], x);
 	  break;
 
 	default:
 	  gcc_unreachable ();
 	}
-      return immed_double_const (xl, xh, mode);
+      wc = wide_int::from_array (tmp, 2, GET_MODE_PRECISION (mode));
+      return immed_wide_int_const (wc, mode);
     }
 
   return NULL_RTX;
@@ -2204,49 +2025,50 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       if (SCALAR_INT_MODE_P (mode))
 	{
-	  double_int coeff0, coeff1;
+	  wide_int coeff0;
+	  wide_int coeff1;
 	  rtx lhs = op0, rhs = op1;
 
-	  coeff0 = double_int_one;
-	  coeff1 = double_int_one;
+	  coeff0 = wide_int::one (GET_MODE_PRECISION (mode));
+	  coeff1 = wide_int::one (GET_MODE_PRECISION (mode));
 
 	  if (GET_CODE (lhs) == NEG)
 	    {
-	      coeff0 = double_int_minus_one;
+	      coeff0 = wide_int::minus_one (GET_MODE_PRECISION (mode));
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == MULT
-		   && CONST_INT_P (XEXP (lhs, 1)))
+		   && CONST_SCALAR_INT_P (XEXP (lhs, 1)))
 	    {
-	      coeff0 = double_int::from_shwi (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::from_rtx (XEXP (lhs, 1), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == ASHIFT
 		   && CONST_INT_P (XEXP (lhs, 1))
                    && INTVAL (XEXP (lhs, 1)) >= 0
-		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (lhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff0 = double_int_zero.set_bit (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::set_bit_in_zero (INTVAL (XEXP (lhs, 1)), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 
 	  if (GET_CODE (rhs) == NEG)
 	    {
-	      coeff1 = double_int_minus_one;
+	      coeff1 = wide_int::minus_one (GET_MODE_PRECISION (mode));
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == MULT
 		   && CONST_INT_P (XEXP (rhs, 1)))
 	    {
-	      coeff1 = double_int::from_shwi (INTVAL (XEXP (rhs, 1)));
+	      coeff1 = wide_int::from_rtx (XEXP (rhs, 1), mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == ASHIFT
 		   && CONST_INT_P (XEXP (rhs, 1))
 		   && INTVAL (XEXP (rhs, 1)) >= 0
-		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (rhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff1 = double_int_zero.set_bit (INTVAL (XEXP (rhs, 1)));
+	      coeff1 = wide_int::set_bit_in_zero (INTVAL (XEXP (rhs, 1)), mode);
 	      rhs = XEXP (rhs, 0);
 	    }
 
@@ -2254,11 +2076,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	    {
 	      rtx orig = gen_rtx_PLUS (mode, op0, op1);
 	      rtx coeff;
-	      double_int val;
 	      bool speed = optimize_function_for_speed_p (cfun);
 
-	      val = coeff0 + coeff1;
-	      coeff = immed_double_int_const (val, mode);
+	      coeff = immed_wide_int_const (coeff0 + coeff1, mode);
 
 	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
 	      return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
@@ -2380,50 +2200,52 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       if (SCALAR_INT_MODE_P (mode))
 	{
-	  double_int coeff0, negcoeff1;
+	  wide_int coeff0;
+	  wide_int negcoeff1;
 	  rtx lhs = op0, rhs = op1;
 
-	  coeff0 = double_int_one;
-	  negcoeff1 = double_int_minus_one;
+	  coeff0 = wide_int::one (GET_MODE_PRECISION (mode));
+	  negcoeff1 = wide_int::minus_one (GET_MODE_PRECISION (mode));
 
 	  if (GET_CODE (lhs) == NEG)
 	    {
-	      coeff0 = double_int_minus_one;
+	      coeff0 = wide_int::minus_one (GET_MODE_PRECISION (mode));
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == MULT
-		   && CONST_INT_P (XEXP (lhs, 1)))
+		   && CONST_SCALAR_INT_P (XEXP (lhs, 1)))
 	    {
-	      coeff0 = double_int::from_shwi (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::from_rtx (XEXP (lhs, 1), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 	  else if (GET_CODE (lhs) == ASHIFT
 		   && CONST_INT_P (XEXP (lhs, 1))
 		   && INTVAL (XEXP (lhs, 1)) >= 0
-		   && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (lhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      coeff0 = double_int_zero.set_bit (INTVAL (XEXP (lhs, 1)));
+	      coeff0 = wide_int::set_bit_in_zero (INTVAL (XEXP (lhs, 1)), mode);
 	      lhs = XEXP (lhs, 0);
 	    }
 
 	  if (GET_CODE (rhs) == NEG)
 	    {
-	      negcoeff1 = double_int_one;
+	      negcoeff1 = wide_int::one (GET_MODE_PRECISION (mode));
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == MULT
 		   && CONST_INT_P (XEXP (rhs, 1)))
 	    {
-	      negcoeff1 = double_int::from_shwi (-INTVAL (XEXP (rhs, 1)));
+	      negcoeff1 = wide_int::from_rtx (XEXP (rhs, 1), mode).neg ();
 	      rhs = XEXP (rhs, 0);
 	    }
 	  else if (GET_CODE (rhs) == ASHIFT
 		   && CONST_INT_P (XEXP (rhs, 1))
 		   && INTVAL (XEXP (rhs, 1)) >= 0
-		   && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+		   && INTVAL (XEXP (rhs, 1)) < GET_MODE_PRECISION (mode))
 	    {
-	      negcoeff1 = double_int_zero.set_bit (INTVAL (XEXP (rhs, 1)));
-	      negcoeff1 = -negcoeff1;
+	      negcoeff1 = wide_int::set_bit_in_zero (INTVAL (XEXP (rhs, 1)),
+						    mode);
+	      negcoeff1 = negcoeff1.neg ();
 	      rhs = XEXP (rhs, 0);
 	    }
 
@@ -2431,11 +2253,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	    {
 	      rtx orig = gen_rtx_MINUS (mode, op0, op1);
 	      rtx coeff;
-	      double_int val;
 	      bool speed = optimize_function_for_speed_p (cfun);
 
-	      val = coeff0 + negcoeff1;
-	      coeff = immed_double_int_const (val, mode);
+	      coeff = immed_wide_int_const (coeff0 + negcoeff1, mode);
 
 	      tem = simplify_gen_binary (MULT, mode, lhs, coeff);
 	      return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
@@ -2587,26 +2407,13 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 	  && trueop1 == CONST1_RTX (mode))
 	return op0;
 
-      /* Convert multiply by constant power of two into shift unless
-	 we are still generating RTL.  This test is a kludge.  */
-      if (CONST_INT_P (trueop1)
-	  && (val = exact_log2 (UINTVAL (trueop1))) >= 0
-	  /* If the mode is larger than the host word size, and the
-	     uppermost bit is set, then this isn't a power of two due
-	     to implicit sign extension.  */
-	  && (width <= HOST_BITS_PER_WIDE_INT
-	      || val != HOST_BITS_PER_WIDE_INT - 1))
-	return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
-
-      /* Likewise for multipliers wider than a word.  */
-      if (CONST_DOUBLE_AS_INT_P (trueop1)
-	  && GET_MODE (op0) == mode
-	  && CONST_DOUBLE_LOW (trueop1) == 0
-	  && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0
-	  && (val < HOST_BITS_PER_DOUBLE_INT - 1
-	      || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT))
-	return simplify_gen_binary (ASHIFT, mode, op0,
-				    GEN_INT (val + HOST_BITS_PER_WIDE_INT));
+      /* Convert multiply by constant power of two into shift.  */
+      if (CONST_SCALAR_INT_P (trueop1))
+	{
+	  val = wide_int::from_rtx (trueop1, mode).exact_log2 ().to_shwi ();
+	  if (val >= 0 && val < GET_MODE_BITSIZE (mode))
+	    return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
+	}
 
       /* x*2 is x+x and x*(-1) is -x */
       if (CONST_DOUBLE_AS_FLOAT_P (trueop1)
@@ -3682,9 +3489,9 @@ rtx
 simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 				 rtx op0, rtx op1)
 {
-  HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
-  HOST_WIDE_INT val;
+#if TARGET_SUPPORTS_WIDE_INT == 0
   unsigned int width = GET_MODE_PRECISION (mode);
+#endif
 
   if (VECTOR_MODE_P (mode)
       && code != VEC_CONCAT
@@ -3877,299 +3684,129 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
   /* We can fold some multi-word operations.  */
   if (GET_MODE_CLASS (mode) == MODE_INT
-      && width == HOST_BITS_PER_DOUBLE_INT
-      && (CONST_DOUBLE_AS_INT_P (op0) || CONST_INT_P (op0))
-      && (CONST_DOUBLE_AS_INT_P (op1) || CONST_INT_P (op1)))
+      && CONST_SCALAR_INT_P (op0)
+      && CONST_SCALAR_INT_P (op1))
     {
-      double_int o0, o1, res, tmp;
-      bool overflow;
-
-      o0 = rtx_to_double_int (op0);
-      o1 = rtx_to_double_int (op1);
-
+      wide_int result;
+      wide_int wop0 = wide_int::from_rtx (op0, mode);
+      bool overflow = false;
+      unsigned int bitsize = GET_MODE_BITSIZE (mode);
+      rtx_mode_t pop1 = std::make_pair (op1, mode); 
+
+#if TARGET_SUPPORTS_WIDE_INT == 0
+      /* This assert keeps the simplification from producing a result
+	 that cannot be represented in a CONST_DOUBLE but a lot of
+	 upstream callers expect that this function never fails to
+	 simplify something and so you if you added this to the test
+	 above the code would die later anyway.  If this assert
+	 happens, you just need to make the port support wide int.  */
+      gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT);
+#endif
       switch (code)
 	{
 	case MINUS:
-	  /* A - B == A + (-B).  */
-	  o1 = -o1;
-
-	  /* Fall through....  */
+	  result = wop0 - pop1;
+	  break;
 
 	case PLUS:
-	  res = o0 + o1;
+	  result = wop0 + pop1;
 	  break;
 
 	case MULT:
-	  res = o0 * o1;
+	  result = wop0 * pop1;
 	  break;
 
 	case DIV:
-          res = o0.divmod_with_overflow (o1, false, TRUNC_DIV_EXPR,
-					 &tmp, &overflow);
+	  result = wop0.div_trunc (pop1, SIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
-
+	  
 	case MOD:
-          tmp = o0.divmod_with_overflow (o1, false, TRUNC_DIV_EXPR,
-					 &res, &overflow);
+	  result = wop0.mod_trunc (pop1, SIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case UDIV:
-          res = o0.divmod_with_overflow (o1, true, TRUNC_DIV_EXPR,
-					 &tmp, &overflow);
+	  result = wop0.div_trunc (pop1, UNSIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case UMOD:
-          tmp = o0.divmod_with_overflow (o1, true, TRUNC_DIV_EXPR,
-					 &res, &overflow);
+	  result = wop0.mod_trunc (pop1, UNSIGNED, &overflow);
 	  if (overflow)
-	    return 0;
+	    return NULL_RTX;
 	  break;
 
 	case AND:
-	  res = o0 & o1;
+	  result = wop0 & pop1;
 	  break;
 
 	case IOR:
-	  res = o0 | o1;
+	  result = wop0 | pop1;
 	  break;
 
 	case XOR:
-	  res = o0 ^ o1;
+	  result = wop0 ^ pop1;
 	  break;
 
 	case SMIN:
-	  res = o0.smin (o1);
+	  result = wop0.smin (pop1);
 	  break;
 
 	case SMAX:
-	  res = o0.smax (o1);
+	  result = wop0.smax (pop1);
 	  break;
 
 	case UMIN:
-	  res = o0.umin (o1);
+	  result = wop0.umin (pop1);
 	  break;
 
 	case UMAX:
-	  res = o0.umax (o1);
-	  break;
-
-	case LSHIFTRT:   case ASHIFTRT:
-	case ASHIFT:
-	case ROTATE:     case ROTATERT:
-	  {
-	    unsigned HOST_WIDE_INT cnt;
-
-	    if (SHIFT_COUNT_TRUNCATED)
-	      {
-		o1.high = 0; 
-		o1.low &= GET_MODE_PRECISION (mode) - 1;
-	      }
-
-	    if (!o1.fits_uhwi ()
-	        || o1.to_uhwi () >= GET_MODE_PRECISION (mode))
-	      return 0;
-
-	    cnt = o1.to_uhwi ();
-	    unsigned short prec = GET_MODE_PRECISION (mode);
-
-	    if (code == LSHIFTRT || code == ASHIFTRT)
-	      res = o0.rshift (cnt, prec, code == ASHIFTRT);
-	    else if (code == ASHIFT)
-	      res = o0.alshift (cnt, prec);
-	    else if (code == ROTATE)
-	      res = o0.lrotate (cnt, prec);
-	    else /* code == ROTATERT */
-	      res = o0.rrotate (cnt, prec);
-	  }
-	  break;
-
-	default:
-	  return 0;
-	}
-
-      return immed_double_int_const (res, mode);
-    }
-
-  if (CONST_INT_P (op0) && CONST_INT_P (op1)
-      && width <= HOST_BITS_PER_WIDE_INT && width != 0)
-    {
-      /* Get the integer argument values in two forms:
-         zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S.  */
-
-      arg0 = INTVAL (op0);
-      arg1 = INTVAL (op1);
-
-      if (width < HOST_BITS_PER_WIDE_INT)
-        {
-          arg0 &= GET_MODE_MASK (mode);
-          arg1 &= GET_MODE_MASK (mode);
-
-          arg0s = arg0;
-	  if (val_signbit_known_set_p (mode, arg0s))
-	    arg0s |= ~GET_MODE_MASK (mode);
-
-          arg1s = arg1;
-	  if (val_signbit_known_set_p (mode, arg1s))
-	    arg1s |= ~GET_MODE_MASK (mode);
-	}
-      else
-	{
-	  arg0s = arg0;
-	  arg1s = arg1;
-	}
-
-      /* Compute the value of the arithmetic.  */
-
-      switch (code)
-	{
-	case PLUS:
-	  val = arg0s + arg1s;
-	  break;
-
-	case MINUS:
-	  val = arg0s - arg1s;
-	  break;
-
-	case MULT:
-	  val = arg0s * arg1s;
-	  break;
-
-	case DIV:
-	  if (arg1s == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = arg0s / arg1s;
-	  break;
-
-	case MOD:
-	  if (arg1s == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = arg0s % arg1s;
+	  result = wop0.umax (pop1);
 	  break;
 
-	case UDIV:
-	  if (arg1 == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = (unsigned HOST_WIDE_INT) arg0 / arg1;
-	  break;
-
-	case UMOD:
-	  if (arg1 == 0
-	      || ((unsigned HOST_WIDE_INT) arg0s
-		  == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
-		  && arg1s == -1))
-	    return 0;
-	  val = (unsigned HOST_WIDE_INT) arg0 % arg1;
-	  break;
-
-	case AND:
-	  val = arg0 & arg1;
-	  break;
-
-	case IOR:
-	  val = arg0 | arg1;
-	  break;
+	case LSHIFTRT:
+	  if (wide_int::from_rtx (op1, mode).neg_p ())
+	    return NULL_RTX;
 
-	case XOR:
-	  val = arg0 ^ arg1;
+	  result = wop0.rshiftu (pop1, bitsize, TRUNC);
 	  break;
-
-	case LSHIFTRT:
-	case ASHIFT:
+	  
 	case ASHIFTRT:
-	  /* Truncate the shift if SHIFT_COUNT_TRUNCATED, otherwise make sure
-	     the value is in range.  We can't return any old value for
-	     out-of-range arguments because either the middle-end (via
-	     shift_truncation_mask) or the back-end might be relying on
-	     target-specific knowledge.  Nor can we rely on
-	     shift_truncation_mask, since the shift might not be part of an
-	     ashlM3, lshrM3 or ashrM3 instruction.  */
-	  if (SHIFT_COUNT_TRUNCATED)
-	    arg1 = (unsigned HOST_WIDE_INT) arg1 % width;
-	  else if (arg1 < 0 || arg1 >= GET_MODE_BITSIZE (mode))
-	    return 0;
-
-	  val = (code == ASHIFT
-		 ? ((unsigned HOST_WIDE_INT) arg0) << arg1
-		 : ((unsigned HOST_WIDE_INT) arg0) >> arg1);
+	  if (wide_int::from_rtx (op1, mode).neg_p ())
+	    return NULL_RTX;
 
-	  /* Sign-extend the result for arithmetic right shifts.  */
-	  if (code == ASHIFTRT && arg0s < 0 && arg1 > 0)
-	    val |= ((unsigned HOST_WIDE_INT) (-1)) << (width - arg1);
+	  result = wop0.rshifts (pop1, bitsize, TRUNC);
 	  break;
+	  
+	case ASHIFT:
+	  if (wide_int::from_rtx (op1, mode).neg_p ())
+	    return NULL_RTX;
 
-	case ROTATERT:
-	  if (arg1 < 0)
-	    return 0;
-
-	  arg1 %= width;
-	  val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
-		 | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
+	  result = wop0.lshift (pop1, bitsize, TRUNC);
 	  break;
-
+	  
 	case ROTATE:
-	  if (arg1 < 0)
-	    return 0;
-
-	  arg1 %= width;
-	  val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
-		 | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
-	  break;
-
-	case COMPARE:
-	  /* Do nothing here.  */
-	  return 0;
-
-	case SMIN:
-	  val = arg0s <= arg1s ? arg0s : arg1s;
-	  break;
-
-	case UMIN:
-	  val = ((unsigned HOST_WIDE_INT) arg0
-		 <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
-	  break;
+	  if (wide_int::from_rtx (op1, mode).neg_p ())
+	    return NULL_RTX;
 
-	case SMAX:
-	  val = arg0s > arg1s ? arg0s : arg1s;
+	  result = wop0.lrotate (pop1);
 	  break;
+	  
+	case ROTATERT:
+	  if (wide_int::from_rtx (op1, mode).neg_p ())
+	    return NULL_RTX;
 
-	case UMAX:
-	  val = ((unsigned HOST_WIDE_INT) arg0
-		 > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
+	  result = wop0.rrotate (pop1);
 	  break;
 
-	case SS_PLUS:
-	case US_PLUS:
-	case SS_MINUS:
-	case US_MINUS:
-	case SS_MULT:
-	case US_MULT:
-	case SS_DIV:
-	case US_DIV:
-	case SS_ASHIFT:
-	case US_ASHIFT:
-	  /* ??? There are simplifications that can be done.  */
-	  return 0;
-
 	default:
-	  gcc_unreachable ();
+	  return NULL_RTX;
 	}
-
-      return gen_int_mode (val, mode);
+      return immed_wide_int_const (result, mode);
     }
 
   return NULL_RTX;
@@ -4837,10 +4474,11 @@ comparison_result (enum rtx_code code, int known_results)
     }
 }
 
-/* Check if the given comparison (done in the given MODE) is actually a
-   tautology or a contradiction.
-   If no simplification is possible, this function returns zero.
-   Otherwise, it returns either const_true_rtx or const0_rtx.  */
+/* Check if the given comparison (done in the given MODE) is actually
+   a tautology or a contradiction.  If the mode is VOID_mode, the
+   comparison is done in "infinite precision".  If no simplification
+   is possible, this function returns zero.  Otherwise, it returns
+   either const_true_rtx or const0_rtx.  */
 
 rtx
 simplify_const_relational_operation (enum rtx_code code,
@@ -4964,59 +4602,24 @@ simplify_const_relational_operation (enum rtx_code code,
 
   /* Otherwise, see if the operands are both integers.  */
   if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
-       && (CONST_DOUBLE_AS_INT_P (trueop0) || CONST_INT_P (trueop0))
-       && (CONST_DOUBLE_AS_INT_P (trueop1) || CONST_INT_P (trueop1)))
+      && CONST_SCALAR_INT_P (trueop0) && CONST_SCALAR_INT_P (trueop1))
     {
-      int width = GET_MODE_PRECISION (mode);
-      HOST_WIDE_INT l0s, h0s, l1s, h1s;
-      unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
-
-      /* Get the two words comprising each integer constant.  */
-      if (CONST_DOUBLE_AS_INT_P (trueop0))
-	{
-	  l0u = l0s = CONST_DOUBLE_LOW (trueop0);
-	  h0u = h0s = CONST_DOUBLE_HIGH (trueop0);
-	}
-      else
-	{
-	  l0u = l0s = INTVAL (trueop0);
-	  h0u = h0s = HWI_SIGN_EXTEND (l0s);
-	}
-
-      if (CONST_DOUBLE_AS_INT_P (trueop1))
-	{
-	  l1u = l1s = CONST_DOUBLE_LOW (trueop1);
-	  h1u = h1s = CONST_DOUBLE_HIGH (trueop1);
-	}
-      else
-	{
-	  l1u = l1s = INTVAL (trueop1);
-	  h1u = h1s = HWI_SIGN_EXTEND (l1s);
-	}
-
-      /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
-	 we have to sign or zero-extend the values.  */
-      if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
-	{
-	  l0u &= GET_MODE_MASK (mode);
-	  l1u &= GET_MODE_MASK (mode);
-
-	  if (val_signbit_known_set_p (mode, l0s))
-	    l0s |= ~GET_MODE_MASK (mode);
-
-	  if (val_signbit_known_set_p (mode, l1s))
-	    l1s |= ~GET_MODE_MASK (mode);
-	}
-      if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
-	h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
-
-      if (h0u == h1u && l0u == l1u)
+      enum machine_mode cmode = mode;
+      wide_int wo0;
+      rtx_mode_t ptrueop1 = std::make_pair (trueop1, cmode);
+
+      /* It would be nice if we really had a mode here.  However, the
+	 largest int representable on the target is as good as
+	 infinite.  */
+      if (mode == VOIDmode)
+	cmode = MAX_MODE_INT;
+      wo0 = wide_int::from_rtx (trueop0, cmode);
+      if (wo0 == ptrueop1)
 	return comparison_result (code, CMP_EQ);
       else
 	{
-	  int cr;
-	  cr = (h0s < h1s || (h0s == h1s && l0u < l1u)) ? CMP_LT : CMP_GT;
-	  cr |= (h0u < h1u || (h0u == h1u && l0u < l1u)) ? CMP_LTU : CMP_GTU;
+	  int cr = wo0.lts_p (ptrueop1) ? CMP_LT : CMP_GT;
+	  cr |= wo0.ltu_p (ptrueop1) ? CMP_LTU : CMP_GTU;
 	  return comparison_result (code, cr);
 	}
     }
@@ -5472,9 +5075,9 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
   return 0;
 }
 
-/* Evaluate a SUBREG of a CONST_INT or CONST_DOUBLE or CONST_FIXED
-   or CONST_VECTOR,
-   returning another CONST_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
+/* Evaluate a SUBREG of a CONST_INT or CONST_WIDE_INT or CONST_DOUBLE
+   or CONST_FIXED or CONST_VECTOR, returning another CONST_INT or
+   CONST_WIDE_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
 
    Works by unpacking OP into a collection of 8-bit values
    represented as a little-endian array of 'unsigned char', selecting by BYTE,
@@ -5484,13 +5087,11 @@ static rtx
 simplify_immed_subreg (enum machine_mode outermode, rtx op,
 		       enum machine_mode innermode, unsigned int byte)
 {
-  /* We support up to 512-bit values (for V8DFmode).  */
   enum {
-    max_bitsize = 512,
     value_bit = 8,
     value_mask = (1 << value_bit) - 1
   };
-  unsigned char value[max_bitsize / value_bit];
+  unsigned char value[MAX_BITSIZE_MODE_ANY_MODE/value_bit];
   int value_start;
   int i;
   int elem;
@@ -5502,6 +5103,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
   rtvec result_v = NULL;
   enum mode_class outer_class;
   enum machine_mode outer_submode;
+  int max_bitsize;
 
   /* Some ports misuse CCmode.  */
   if (GET_MODE_CLASS (outermode) == MODE_CC && CONST_INT_P (op))
@@ -5511,6 +5113,10 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
   if (COMPLEX_MODE_P (outermode))
     return NULL_RTX;
 
+  /* We support any size mode.  */
+  max_bitsize = MAX (GET_MODE_BITSIZE (outermode), 
+		     GET_MODE_BITSIZE (innermode));
+
   /* Unpack the value.  */
 
   if (GET_CODE (op) == CONST_VECTOR)
@@ -5560,8 +5166,20 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	    *vp++ = INTVAL (el) < 0 ? -1 : 0;
 	  break;
 
+	case CONST_WIDE_INT:
+	  {
+	    wide_int val = wide_int::from_rtx (el, innermode);
+	    unsigned char extend = val.sign_mask ();
+
+	    for (i = 0; i < elem_bitsize; i += value_bit) 
+	      *vp++ = val.extract_to_hwi (i, value_bit);
+	    for (; i < elem_bitsize; i += value_bit)
+	      *vp++ = extend;
+	  }
+	  break;
+
 	case CONST_DOUBLE:
-	  if (GET_MODE (el) == VOIDmode)
+	  if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (el) == VOIDmode)
 	    {
 	      unsigned char extend = 0;
 	      /* If this triggers, someone should have generated a
@@ -5584,7 +5202,8 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	    }
 	  else
 	    {
-	      long tmp[max_bitsize / 32];
+	      /* This is big enough for anything on the platform.  */
+	      long tmp[MAX_BITSIZE_MODE_ANY_MODE / 32];
 	      int bitsize = GET_MODE_BITSIZE (GET_MODE (el));
 
 	      gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (el)));
@@ -5704,24 +5323,27 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	case MODE_INT:
 	case MODE_PARTIAL_INT:
 	  {
-	    unsigned HOST_WIDE_INT hi = 0, lo = 0;
-
-	    for (i = 0;
-		 i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
-		 i += value_bit)
-	      lo |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
-	    for (; i < elem_bitsize; i += value_bit)
-	      hi |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask)
-		     << (i - HOST_BITS_PER_WIDE_INT);
-
-	    /* immed_double_const doesn't call trunc_int_for_mode.  I don't
-	       know why.  */
-	    if (elem_bitsize <= HOST_BITS_PER_WIDE_INT)
-	      elems[elem] = gen_int_mode (lo, outer_submode);
-	    else if (elem_bitsize <= HOST_BITS_PER_DOUBLE_INT)
-	      elems[elem] = immed_double_const (lo, hi, outer_submode);
-	    else
-	      return NULL_RTX;
+	    int u;
+	    int base = 0;
+	    int units 
+	      = (GET_MODE_BITSIZE (outer_submode) + HOST_BITS_PER_WIDE_INT - 1) 
+	      / HOST_BITS_PER_WIDE_INT;
+	    HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+	    wide_int r;
+
+	    for (u = 0; u < units; u++) 
+	      {
+		unsigned HOST_WIDE_INT buf = 0;
+		for (i = 0; 
+		     i < HOST_BITS_PER_WIDE_INT && base + i < elem_bitsize; 
+		     i += value_bit)
+		  buf |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
+
+		tmp[u] = buf;
+		base += HOST_BITS_PER_WIDE_INT;
+	      }
+	    r = wide_int::from_array (tmp, units, GET_MODE_PRECISION (outer_submode));
+	    elems[elem] = immed_wide_int_const (r, outer_submode);
 	  }
 	  break;
 
@@ -5729,7 +5351,7 @@ simplify_immed_subreg (enum machine_mode outermode, rtx op,
 	case MODE_DECIMAL_FLOAT:
 	  {
 	    REAL_VALUE_TYPE r;
-	    long tmp[max_bitsize / 32];
+	    long tmp[MAX_BITSIZE_MODE_ANY_INT / 32];
 
 	    /* real_from_target wants its input in words affected by
 	       FLOAT_WORDS_BIG_ENDIAN.  However, we ignore this,
diff --git a/gcc/testsuite/ada/acats/ada95.lst b/gcc/testsuite/ada/acats/ada95.lst
new file mode 100644
index 0000000..839d5df
--- /dev/null
+++ b/gcc/testsuite/ada/acats/ada95.lst
@@ -0,0 +1,31 @@
+ac3106a
+c34005p
+c34005r
+c34005s
+c34005u
+c34005v
+c34006g
+c34006j
+c34006l
+c34008a
+c3a0014
+c41103b
+c41203b
+c41306a
+c460a01
+c650001
+c74302b
+c74306a
+c85014a
+c85014b
+c85014c
+c87b26b
+c87b41a
+c99004a
+cb40005
+cc3019c
+cc51b03
+cc51d02
+cd10002
+cdd2a03
+cxac005
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr33992.x b/gcc/testsuite/gcc.c-torture/execute/pr33992.x
new file mode 100644
index 0000000..57e9840
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr33992.x
@@ -0,0 +1,7 @@
+load_lib target-supports.exp
+
+if { [ check_effective_target_nonpic ] } {
+        return 0
+}
+
+return 1
diff --git a/gcc/testsuite/gfortran.dg/module_md5_1.f90 b/gcc/testsuite/gfortran.dg/module_md5_1.f90
new file mode 100644
index 0000000..1f522cb
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/module_md5_1.f90
@@ -0,0 +1,13 @@
+! Check that we can write a module file, that it has a correct MD5 sum,
+! and that we can read it back.
+!
+! { dg-do compile }
+module foo
+  integer(kind=4), parameter :: pi = 3_4
+end module foo
+
+program test
+  use foo
+  print *, pi
+end program test
+! { dg-final { scan-module "foo" "MD5:510304affe70481794fecdb22fc9ca0c" } }
diff --git a/gcc/tree-ssa-address.c b/gcc/tree-ssa-address.c
index cfd42ad..33fe8df 100644
--- a/gcc/tree-ssa-address.c
+++ b/gcc/tree-ssa-address.c
@@ -189,15 +189,18 @@ addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
   struct mem_addr_template *templ;
 
   if (addr->step && !integer_onep (addr->step))
-    st = immed_double_int_const (tree_to_double_int (addr->step), pointer_mode);
+    st = immed_wide_int_const (wide_int::from_tree (addr->step),
+			       TYPE_MODE (TREE_TYPE (addr->step)));
   else
     st = NULL_RTX;
 
   if (addr->offset && !integer_zerop (addr->offset))
-    off = immed_double_int_const
-	    (tree_to_double_int (addr->offset)
-	     .sext (TYPE_PRECISION (TREE_TYPE (addr->offset))),
-	     pointer_mode);
+    {
+      wide_int dc = wide_int::from_tree (addr->offset);
+      dc = dc.sforce_to_size (TYPE_PRECISION (TREE_TYPE (addr->offset)));
+      off = immed_wide_int_const (dc,
+			       TYPE_MODE (TREE_TYPE (addr->offset)));
+    }
   else
     off = NULL_RTX;
 
diff --git a/gcc/tree.c b/gcc/tree.c
index d8f2424..22fc583 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -59,6 +59,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "except.h"
 #include "debug.h"
 #include "intl.h"
+#include "wide-int.h"
 
 /* Tree code classes.  */
 
@@ -1067,6 +1068,33 @@ double_int_to_tree (tree type, double_int cst)
   return build_int_cst_wide (type, cst.low, cst.high);
 }
 
+/* Constructs tree in type TYPE from with value given by CST.  Signedness
+   of CST is assumed to be the same as the signedness of TYPE.  */
+
+tree
+wide_int_to_tree (tree type, const wide_int &cst)
+{
+  wide_int v;
+  unsigned int new_prec = TYPE_PRECISION (type);
+  
+  gcc_assert (cst.get_len () <= 2);
+  SignOp sgn = TYPE_UNSIGNED (type) ? UNSIGNED : SIGNED;
+
+  /* This is something of a temporary hack.  The current rep of a
+     INT_CST looks at all of the bits, even those past the precision
+     of the type.  So we have to accomodate this.  The first test
+     checks to see if the type we want to make this is shorter than
+     the current rep, but the second block just goes and extends what
+     is there to the full size of the INT_CST.  */ 
+  if (new_prec < cst.get_precision ())
+    v = cst.zext (TYPE_PRECISION (type))
+      .force_to_size (HOST_BITS_PER_DOUBLE_INT, sgn);
+  else
+    v = cst.force_to_size (HOST_BITS_PER_DOUBLE_INT, sgn);
+
+  return build_int_cst_wide (type, v.elt (0), v.elt (1));
+}
+
 /* Returns true if CST fits into range of TYPE.  Signedness of CST is assumed
    to be the same as the signedness of TYPE.  */
 
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index 8108413..5bff082 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -3523,6 +3523,23 @@ loc_cmp (rtx x, rtx y)
       default:
 	gcc_unreachable ();
       }
+  if (CONST_WIDE_INT_P (x))
+    {
+      /* Compare the vector length first.  */
+      if (CONST_WIDE_INT_NUNITS (x) >= CONST_WIDE_INT_NUNITS (y))
+	return 1;
+      else if (CONST_WIDE_INT_NUNITS (x) < CONST_WIDE_INT_NUNITS (y))
+	return -1;
+
+      /* Compare the vectors elements.  */;
+      for (j = CONST_WIDE_INT_NUNITS (x) - 1; j >= 0 ; j--)
+	{
+	  if (CONST_WIDE_INT_ELT (x, j) < CONST_WIDE_INT_ELT (y, j))
+	    return -1;
+	  if (CONST_WIDE_INT_ELT (x, j) > CONST_WIDE_INT_ELT (y, j))
+	    return 1;
+	}
+    }
 
   return 0;
 }
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 2532d80..7cca674 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -3406,6 +3406,7 @@ const_rtx_hash_1 (rtx *xp, void *data)
   enum rtx_code code;
   hashval_t h, *hp;
   rtx x;
+  int i;
 
   x = *xp;
   code = GET_CODE (x);
@@ -3416,12 +3417,12 @@ const_rtx_hash_1 (rtx *xp, void *data)
     {
     case CONST_INT:
       hwi = INTVAL (x);
+
     fold_hwi:
       {
 	int shift = sizeof (hashval_t) * CHAR_BIT;
 	const int n = sizeof (HOST_WIDE_INT) / sizeof (hashval_t);
-	int i;
-
+	
 	h ^= (hashval_t) hwi;
 	for (i = 1; i < n; ++i)
 	  {
@@ -3431,8 +3432,16 @@ const_rtx_hash_1 (rtx *xp, void *data)
       }
       break;
 
+    case CONST_WIDE_INT:
+      hwi = GET_MODE_PRECISION (mode);
+      {
+	for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+	  hwi ^= CONST_WIDE_INT_ELT (x, i);
+	goto fold_hwi;
+      }
+
     case CONST_DOUBLE:
-      if (mode == VOIDmode)
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && mode == VOIDmode)
 	{
 	  hwi = CONST_DOUBLE_LOW (x) ^ CONST_DOUBLE_HIGH (x);
 	  goto fold_hwi;

[-- Attachment #3: p5-7.clog --]
[-- Type: text/plain, Size: 4620 bytes --]

2013-05-02  Kenneth Zadeck <zadeck@naturalbridge.com>

	* alias.c  (rtx_equal_for_memref_p): Fixed comment.
	* builtins.c (c_getstr, c_readstr, expand_builtin_signbit): 
	Make to work with any size int.
	* combine.c (try_combine, subst): Changed to support any 
	size integer.
	* coretypes.h (hwivec_def, hwivec, const_hwivec): New.
	* cse.c (hash_rtx_cb): Added CONST_WIDE_INT case are
	modified DOUBLE_INT case.
	* cselib.c (rtx_equal_for_cselib_1): Converted cases to 
	CASE_CONST_UNIQUE.
	(cselib_hash_rtx): Added CONST_WIDE_INT case.
	* defaults.h (TARGET_SUPPORTS_WIDE_INT): New.
	* doc/rtl.texi (CONST_DOUBLE, CONST_WIDE_INT): Updated.
	* doc/tm.texi (TARGET_SUPPORTS_WIDE_INT): New.	
	* doc/tm.texi.in (TARGET_SUPPORTS_WIDE_INT): New.
	* dojump.c (prefer_and_bit_test): Use wide int api.
	* dwarf2out.c (get_full_len): New function.
	(dw_val_equal_p, size_of_loc_descr,
	output_loc_operands, print_die, attr_checksum, same_dw_val_p,
	size_of_die, value_format, output_die, mem_loc_descriptor,
	loc_descriptor, extract_int, add_const_value_attribute,
	hash_loc_operands, compare_loc_operands): Add support for wide-ints.
	(add_AT_wide): New function.
	* dwarf2out.h (enum dw_val_class): Added dw_val_class_wide_int.
	* emit-rtl.c (const_wide_int_htab): Add marking.
	(const_wide_int_htab_hash, const_wide_int_htab_eq,
	lookup_const_wide_int, immed_wide_int_const): New functions.
	(const_double_htab_hash, const_double_htab_eq,
	rtx_to_double_int, immed_double_const): Conditionally 
	changed CONST_DOUBLE behavior.
 	(immed_double_const, init_emit_once): Changed to support wide-int.
	* explow.c (plus_constant): Now uses wide-int api.
	* expmed.c (mask_rtx, lshift_value): Now uses wide-int.
 	(expand_mult, expand_smod_pow2): Make to work with any size int.
	(make_tree): Added CONST_WIDE_INT case.
	* expr.c (convert_modes): Added support for any size int.
	(emit_group_load_1): Added todo for place that still does not
	allow large ints.
	(store_expr, expand_constructor): Fixed comments.
	(expand_expr_real_2, expand_expr_real_1,
	reduce_to_bit_field_precision, const_vector_from_tree):
	Converted to use wide-int api.
	* final.c (output_addr_const): Added CONST_WIDE_INT case.
	* genemit.c (gen_exp): Added CONST_WIDE_INT case.
	* gengenrtl.c (excluded_rtx): Added CONST_WIDE_INT case.
	* gengtype-lex.l (CXX_KEYWORD): Added static.
	(<in_struct>) added "^".
	* gengtype-parse.c (require_template_declaration) Added enum case.
	* gengtype.c (wide-int): New type.
	* genpreds.c (write_one_predicate_function): Fixed comment.
	(add_constraint): Added CONST_WIDE_INT test.
	(write_tm_constrs_h): Do not emit hval or lval if target
	supports wide integers.
	* gensupport.c (std_preds): Added const_wide_int_operand and
	const_scalar_int_operand.
	* optabs.c (expand_subword_shift, expand_doubleword_shift,
	expand_absneg_bit, expand_absneg_bit, expand_copysign_absneg,
	expand_copysign_bit): Made to work with any size int.  
	* postreload.c (reload_cse_simplify_set):  Now uses wide-int api.
	* print-rtl.c (print_rtx): Added CONST_WIDE_INT case.
	* read-rtl.c (validate_const_wide_int): New function.
	(read_rtx_code): Added CONST_WIDE_INT case.
	* recog.c (const_scalar_int_operand, const_double_operand):
	New versions if target supports wide integers.
	(const_wide_int_operand): New function.
	* rtl.c (DEF_RTL_EXPR): Added CONST_WIDE_INT case.
	(rtx_size): Ditto.
	(rtx_alloc_stat, hwivec_output_hex, hwivec_check_failed_bounds):
	New functions.
	(iterative_hash_rtx): Added CONST_WIDE_INT case.
	* rtl.def (CONST_WIDE_INT): New.
	* rtl.h (hwivec_def): New function.
	(HWI_GET_NUM_ELEM, HWI_PUT_NUM_ELEM, CONST_WIDE_INT_P,
	CONST_SCALAR_INT_P, XHWIVEC_ELT, HWIVEC_CHECK, CONST_WIDE_INT_VEC,
	CONST_WIDE_INT_NUNITS, CONST_WIDE_INT_ELT, rtx_alloc_v): New macros.
	(chain_next): Added hwiv case.
	(CASE_CONST_SCALAR_INT, CONST_INT, CONST_WIDE_INT):  Added new
	defs if target supports wide ints.
	* rtlanal.c (commutative_operand_precedence, split_double):
	Added CONST_WIDE_INT case.
	* sched-vis.c (print_value): Added CONST_WIDE_INT case are
	modified DOUBLE_INT case.
	* sel-sched-ir.c (lhs_and_rhs_separable_p): Fixed comment
	* simplify-rtx.c (mode_signbit_p,
	simplify_const_unary_operation, simplify_binary_operation_1,
	simplify_const_binary_operation,
	simplify_const_relational_operation, simplify_immed_subreg):
	Make work with any size int.  .
	* tree-ssa-address.c (addr_for_mem_ref): Changes to use
	wide-int rather than double-int.
	* tree.c (wide_int_to_tree): New function.
	* var-tracking.c (loc_cmp): Added CONST_WIDE_INT case.
	* varasm.c (const_rtx_hash_1): Added CONST_WIDE_INT case.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math - builtins.c - the first of the tree level patches for wide-int
  2013-04-17  7:34                                                                                   ` patch to fix constant math - builtins.c - the first of the tree level patches for wide-int Kenneth Zadeck
@ 2013-05-02 17:53                                                                                     ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-05-02 17:53 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, rdsandiford, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 1016 bytes --]

The only changes here were account for the changes to the wide-int api.

On 04/16/2013 04:24 PM, Kenneth Zadeck wrote:
> Richard, this is the first of the tree level patches so that you can 
> see how the wide-int changes will effect the tree level.   This patch 
> converts builtins.c so that it does not in any way assume that 
> tree-cst holds two HWIs.   The patch divides all math into two 
> categories:   Things that are always so small that we can easily 
> assume that the math can be done using a single HWI and everything 
> else.   The things that it assumes can easily be done with a HWI are 
> guarded with assertions.   The everything else is done with wide-int.  
> Everything else in this patch is additional abi to support this.
>
> The idea is that each pass will be converted, 1 pass per patch in this 
> way.    Once everything does not depend on the internals of tree-cst 
> as they do now, then tree-cst will be converted to have an array 
> inside of it rather than just two hwis.
>
> Kenny


[-- Attachment #2: t1-2.diff --]
[-- Type: text/x-patch, Size: 39668 bytes --]

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 0c587d1..181784b 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -339,8 +339,8 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
       if (TREE_CODE (addr) == BIT_AND_EXPR
 	  && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
 	{
-	  align = (TREE_INT_CST_LOW (TREE_OPERAND (addr, 1))
-		    & -TREE_INT_CST_LOW (TREE_OPERAND (addr, 1)));
+	  align = (tree_to_hwi (TREE_OPERAND (addr, 1))
+		   & -tree_to_hwi (TREE_OPERAND (addr, 1)));
 	  align *= BITS_PER_UNIT;
 	  addr = TREE_OPERAND (addr, 0);
 	}
@@ -357,7 +357,7 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
 	    {
 	      unsigned HOST_WIDE_INT step = 1;
 	      if (TMR_STEP (exp))
-		step = TREE_INT_CST_LOW (TMR_STEP (exp));
+		step = tree_to_hwi (TMR_STEP (exp));
 	      align = MIN (align, (step & -step) * BITS_PER_UNIT);
 	    }
 	  if (TMR_INDEX2 (exp))
@@ -379,7 +379,8 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
 	  bitpos += ptr_bitpos;
 	  if (TREE_CODE (exp) == MEM_REF
 	      || TREE_CODE (exp) == TARGET_MEM_REF)
-	    bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT;
+	    bitpos += wide_int::from_tree (TREE_OPERAND (exp, 1))
+	      .to_shwi () * BITS_PER_UNIT;
 	}
     }
   else if (TREE_CODE (exp) == STRING_CST)
@@ -408,23 +409,23 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
 	}
       else
 	next_offset = NULL;
-      if (host_integerp (offset, 1))
+      if (tree_fits_uhwi_p (offset))
 	{
 	  /* Any overflow in calculating offset_bits won't change
 	     the alignment.  */
 	  unsigned offset_bits
-	    = ((unsigned) tree_low_cst (offset, 1) * BITS_PER_UNIT);
+	    = ((unsigned) tree_to_hwi (offset) * BITS_PER_UNIT);
 
 	  if (offset_bits)
 	    inner = MIN (inner, (offset_bits & -offset_bits));
 	}
       else if (TREE_CODE (offset) == MULT_EXPR
-	       && host_integerp (TREE_OPERAND (offset, 1), 1))
+	       && tree_fits_uhwi_p (TREE_OPERAND (offset, 1)))
 	{
 	  /* Any overflow in calculating offset_factor won't change
 	     the alignment.  */
 	  unsigned offset_factor
-	    = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
+	    = ((unsigned) tree_to_hwi (TREE_OPERAND (offset, 1))
 	       * BITS_PER_UNIT);
 
 	  if (offset_factor)
@@ -515,7 +516,7 @@ get_pointer_alignment_1 (tree exp, unsigned int *alignp,
   else if (TREE_CODE (exp) == INTEGER_CST)
     {
       *alignp = BIGGEST_ALIGNMENT;
-      *bitposp = ((TREE_INT_CST_LOW (exp) * BITS_PER_UNIT)
+      *bitposp = ((tree_to_hwi (exp) * BITS_PER_UNIT)
 		  & (BIGGEST_ALIGNMENT - 1));
       return true;
     }
@@ -624,10 +625,10 @@ c_strlen (tree src, int only_value)
      a null character if we can represent it as a single HOST_WIDE_INT.  */
   if (offset_node == 0)
     offset = 0;
-  else if (! host_integerp (offset_node, 0))
+  else if (!tree_fits_shwi_p (offset_node))
     offset = -1;
   else
-    offset = tree_low_cst (offset_node, 0);
+    offset = tree_to_hwi (offset_node);
 
   /* If the offset is known to be out of bounds, warn, and call strlen at
      runtime.  */
@@ -665,11 +666,11 @@ c_getstr (tree src)
 
   if (offset_node == 0)
     return TREE_STRING_POINTER (src);
-  else if (!host_integerp (offset_node, 1)
+  else if (!tree_fits_uhwi_p (offset_node)
 	   || compare_tree_int (offset_node, TREE_STRING_LENGTH (src) - 1) > 0)
     return 0;
 
-  return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
+  return TREE_STRING_POINTER (src) + tree_to_uhwi (offset_node);
 }
 
 /* Return a constant integer corresponding to target reading
@@ -723,7 +724,9 @@ target_char_cast (tree cst, char *p)
       || CHAR_TYPE_SIZE > HOST_BITS_PER_WIDE_INT)
     return 1;
 
-  val = TREE_INT_CST_LOW (cst);
+  /* Do not care if it fits or not right here.  */
+  val = tree_to_hwi (cst);
+
   if (CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT)
     val &= (((unsigned HOST_WIDE_INT) 1) << CHAR_TYPE_SIZE) - 1;
 
@@ -3168,7 +3171,7 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len,
 	return NULL_RTX;
 
       /* If LEN is not constant, call the normal function.  */
-      if (! host_integerp (len, 1))
+      if (! tree_fits_uhwi_p (len))
 	return NULL_RTX;
 
       len_rtx = expand_normal (len);
@@ -3403,7 +3406,7 @@ expand_builtin_strncpy (tree exp, rtx target)
       tree slen = c_strlen (src, 1);
 
       /* We must be passed a constant len and src parameter.  */
-      if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1))
+      if (!tree_fits_uhwi_p (len) || !slen || !tree_fits_uhwi_p (slen))
 	return NULL_RTX;
 
       slen = size_binop_loc (loc, PLUS_EXPR, slen, ssize_int (1));
@@ -3417,15 +3420,15 @@ expand_builtin_strncpy (tree exp, rtx target)
 	  const char *p = c_getstr (src);
 	  rtx dest_mem;
 
-	  if (!p || dest_align == 0 || !host_integerp (len, 1)
-	      || !can_store_by_pieces (tree_low_cst (len, 1),
+	  if (!p || dest_align == 0 || !tree_fits_uhwi_p (len)
+	      || !can_store_by_pieces (tree_to_uhwi (len),
 				       builtin_strncpy_read_str,
 				       CONST_CAST (char *, p),
 				       dest_align, false))
 	    return NULL_RTX;
 
 	  dest_mem = get_memory_rtx (dest, len);
-	  store_by_pieces (dest_mem, tree_low_cst (len, 1),
+	  store_by_pieces (dest_mem, tree_to_uhwi (len),
 			   builtin_strncpy_read_str,
 			   CONST_CAST (char *, p), dest_align, false, 0);
 	  dest_mem = force_operand (XEXP (dest_mem, 0), target);
@@ -3558,13 +3561,13 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
        * the coefficients by pieces (in the required modes).
        * We can't pass builtin_memset_gen_str as that emits RTL.  */
       c = 1;
-      if (host_integerp (len, 1)
-	  && can_store_by_pieces (tree_low_cst (len, 1),
+      if (tree_fits_uhwi_p (len)
+	  && can_store_by_pieces (tree_to_hwi (len),
 				  builtin_memset_read_str, &c, dest_align,
 				  true))
 	{
 	  val_rtx = force_reg (val_mode, val_rtx);
-	  store_by_pieces (dest_mem, tree_low_cst (len, 1),
+	  store_by_pieces (dest_mem, tree_to_hwi (len),
 			   builtin_memset_gen_str, val_rtx, dest_align,
 			   true, 0);
 	}
@@ -3583,11 +3586,11 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
 
   if (c)
     {
-      if (host_integerp (len, 1)
-	  && can_store_by_pieces (tree_low_cst (len, 1),
+      if (tree_fits_uhwi_p (len)
+	  && can_store_by_pieces (tree_to_hwi (len),
 				  builtin_memset_read_str, &c, dest_align,
 				  true))
-	store_by_pieces (dest_mem, tree_low_cst (len, 1),
+	store_by_pieces (dest_mem, tree_to_hwi (len),
 			 builtin_memset_read_str, &c, dest_align, true, 0);
       else if (!set_storage_via_setmem (dest_mem, len_rtx,
 					gen_int_mode (c, val_mode),
@@ -4492,7 +4495,7 @@ expand_builtin_frame_address (tree fndecl, tree exp)
   if (call_expr_nargs (exp) == 0)
     /* Warning about missing arg was already issued.  */
     return const0_rtx;
-  else if (! host_integerp (CALL_EXPR_ARG (exp, 0), 1))
+  else if (! tree_fits_uhwi_p (CALL_EXPR_ARG (exp, 0)))
     {
       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
 	error ("invalid argument to %<__builtin_frame_address%>");
@@ -4504,7 +4507,7 @@ expand_builtin_frame_address (tree fndecl, tree exp)
     {
       rtx tem
 	= expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl),
-				      tree_low_cst (CALL_EXPR_ARG (exp, 0), 1));
+				      tree_to_uhwi (CALL_EXPR_ARG (exp, 0)));
 
       /* Some ports cannot access arbitrary stack frames.  */
       if (tem == NULL)
@@ -4558,7 +4561,7 @@ expand_builtin_alloca (tree exp, bool cannot_accumulate)
 
   /* Compute the alignment.  */
   align = (alloca_with_align
-	   ? TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 1))
+	   ? tree_to_uhwi (CALL_EXPR_ARG (exp, 1))
 	   : BIGGEST_ALIGNMENT);
 
   /* Allocate the desired space.  */
@@ -5390,7 +5393,7 @@ expand_builtin_atomic_compare_exchange (enum machine_mode mode, tree exp,
 
   weak = CALL_EXPR_ARG (exp, 3);
   is_weak = false;
-  if (host_integerp (weak, 0) && tree_low_cst (weak, 0) != 0)
+  if (tree_fits_shwi_p (weak) && tree_to_hwi (weak) != 0)
     is_weak = true;
 
   oldval = expect;
@@ -8026,8 +8029,9 @@ fold_builtin_int_roundingfn (location_t loc, tree fndecl, tree arg)
 	{
 	  tree itype = TREE_TYPE (TREE_TYPE (fndecl));
 	  tree ftype = TREE_TYPE (arg);
-	  double_int val;
+	  wide_int val;
 	  REAL_VALUE_TYPE r;
+	  bool fail = false;
 
 	  switch (DECL_FUNCTION_CODE (fndecl))
 	    {
@@ -8053,9 +8057,10 @@ fold_builtin_int_roundingfn (location_t loc, tree fndecl, tree arg)
 	      gcc_unreachable ();
 	    }
 
-	  real_to_integer2 ((HOST_WIDE_INT *)&val.low, &val.high, &r);
-	  if (double_int_fits_to_tree_p (itype, val))
-	    return double_int_to_tree (itype, val);
+	  val = real_to_integer (&r, &fail, 
+				 TYPE_PRECISION (itype));
+	  if (!fail)
+	    return wide_int_to_tree (itype, val);
 	}
     }
 
@@ -8088,100 +8093,40 @@ fold_builtin_bitop (tree fndecl, tree arg)
   /* Optimize for constant argument.  */
   if (TREE_CODE (arg) == INTEGER_CST && !TREE_OVERFLOW (arg))
     {
-      HOST_WIDE_INT hi, width, result;
-      unsigned HOST_WIDE_INT lo;
-      tree type;
-
-      type = TREE_TYPE (arg);
-      width = TYPE_PRECISION (type);
-      lo = TREE_INT_CST_LOW (arg);
-
-      /* Clear all the bits that are beyond the type's precision.  */
-      if (width > HOST_BITS_PER_WIDE_INT)
-	{
-	  hi = TREE_INT_CST_HIGH (arg);
-	  if (width < HOST_BITS_PER_DOUBLE_INT)
-	    hi &= ~((unsigned HOST_WIDE_INT) (-1)
-		    << (width - HOST_BITS_PER_WIDE_INT));
-	}
-      else
-	{
-	  hi = 0;
-	  if (width < HOST_BITS_PER_WIDE_INT)
-	    lo &= ~((unsigned HOST_WIDE_INT) (-1) << width);
-	}
+      wide_int warg = wide_int::from_tree (arg);
+      wide_int result;
 
       switch (DECL_FUNCTION_CODE (fndecl))
 	{
 	CASE_INT_FN (BUILT_IN_FFS):
-	  if (lo != 0)
-	    result = ffs_hwi (lo);
-	  else if (hi != 0)
-	    result = HOST_BITS_PER_WIDE_INT + ffs_hwi (hi);
-	  else
-	    result = 0;
+	  result = warg.ffs ();
 	  break;
 
 	CASE_INT_FN (BUILT_IN_CLZ):
-	  if (hi != 0)
-	    result = width - floor_log2 (hi) - 1 - HOST_BITS_PER_WIDE_INT;
-	  else if (lo != 0)
-	    result = width - floor_log2 (lo) - 1;
-	  else if (! CLZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (type), result))
-	    result = width;
+	  result = warg.clz ();
 	  break;
 
 	CASE_INT_FN (BUILT_IN_CTZ):
-	  if (lo != 0)
-	    result = ctz_hwi (lo);
-	  else if (hi != 0)
-	    result = HOST_BITS_PER_WIDE_INT + ctz_hwi (hi);
-	  else if (! CTZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (type), result))
-	    result = width;
+	  result = warg.ctz ();
 	  break;
 
 	CASE_INT_FN (BUILT_IN_CLRSB):
-	  if (width > HOST_BITS_PER_WIDE_INT
-	      && (hi & ((unsigned HOST_WIDE_INT) 1
-			<< (width - HOST_BITS_PER_WIDE_INT - 1))) != 0)
-	    {
-	      hi = ~hi & ~((unsigned HOST_WIDE_INT) (-1)
-			   << (width - HOST_BITS_PER_WIDE_INT - 1));
-	      lo = ~lo;
-	    }
-	  else if (width <= HOST_BITS_PER_WIDE_INT
-		   && (lo & ((unsigned HOST_WIDE_INT) 1 << (width - 1))) != 0)
-	    lo = ~lo & ~((unsigned HOST_WIDE_INT) (-1) << (width - 1));
-	  if (hi != 0)
-	    result = width - floor_log2 (hi) - 2 - HOST_BITS_PER_WIDE_INT;
-	  else if (lo != 0)
-	    result = width - floor_log2 (lo) - 2;
-	  else
-	    result = width - 1;
+	  result = warg.clrsb ();
 	  break;
 
 	CASE_INT_FN (BUILT_IN_POPCOUNT):
-	  result = 0;
-	  while (lo)
-	    result++, lo &= lo - 1;
-	  while (hi)
-	    result++, hi &= (unsigned HOST_WIDE_INT) hi - 1;
+	  result = warg.popcount ();
 	  break;
 
 	CASE_INT_FN (BUILT_IN_PARITY):
-	  result = 0;
-	  while (lo)
-	    result++, lo &= lo - 1;
-	  while (hi)
-	    result++, hi &= (unsigned HOST_WIDE_INT) hi - 1;
-	  result &= 1;
+	  result = warg.parity ();
 	  break;
 
 	default:
 	  gcc_unreachable ();
 	}
 
-      return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), result);
+      return wide_int_to_tree (TREE_TYPE (TREE_TYPE (fndecl)), result);
     }
 
   return NULL_TREE;
@@ -8198,49 +8143,25 @@ fold_builtin_bswap (tree fndecl, tree arg)
   /* Optimize constant value.  */
   if (TREE_CODE (arg) == INTEGER_CST && !TREE_OVERFLOW (arg))
     {
-      HOST_WIDE_INT hi, width, r_hi = 0;
-      unsigned HOST_WIDE_INT lo, r_lo = 0;
       tree type = TREE_TYPE (TREE_TYPE (fndecl));
 
-      width = TYPE_PRECISION (type);
-      lo = TREE_INT_CST_LOW (arg);
-      hi = TREE_INT_CST_HIGH (arg);
-
       switch (DECL_FUNCTION_CODE (fndecl))
 	{
 	  case BUILT_IN_BSWAP16:
 	  case BUILT_IN_BSWAP32:
 	  case BUILT_IN_BSWAP64:
 	    {
-	      int s;
-
-	      for (s = 0; s < width; s += 8)
-		{
-		  int d = width - s - 8;
-		  unsigned HOST_WIDE_INT byte;
-
-		  if (s < HOST_BITS_PER_WIDE_INT)
-		    byte = (lo >> s) & 0xff;
-		  else
-		    byte = (hi >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff;
-
-		  if (d < HOST_BITS_PER_WIDE_INT)
-		    r_lo |= byte << d;
-		  else
-		    r_hi |= byte << (d - HOST_BITS_PER_WIDE_INT);
-		}
+	      wide_int::SignOp sgn = TYPE_UNSIGNED (type) 
+		? wide_int::UNSIGNED : wide_int::SIGNED;
+	      tree result = 
+		wide_int_to_tree (type, 
+				  wide_int::from_tree (arg)
+				  .force_to_size (TYPE_PRECISION (type), sgn).bswap ());
+	      return result;
 	    }
-
-	    break;
-
 	default:
 	  gcc_unreachable ();
 	}
-
-      if (width < HOST_BITS_PER_WIDE_INT)
-	return build_int_cst (type, r_lo);
-      else
-	return build_int_cst_wide (type, r_lo, r_hi);
     }
 
   return NULL_TREE;
@@ -8553,9 +8474,9 @@ fold_builtin_powi (location_t loc, tree fndecl ATTRIBUTE_UNUSED,
   if (real_onep (arg0))
     return omit_one_operand_loc (loc, type, build_real (type, dconst1), arg1);
 
-  if (host_integerp (arg1, 0))
+  if (tree_fits_shwi_p (arg1))
     {
-      HOST_WIDE_INT c = TREE_INT_CST_LOW (arg1);
+      HOST_WIDE_INT c = tree_to_hwi (arg1);
 
       /* Evaluate powi at compile-time.  */
       if (TREE_CODE (arg0) == REAL_CST
@@ -8652,7 +8573,7 @@ fold_builtin_memset (location_t loc, tree dest, tree c, tree len,
       || ! validate_arg (len, INTEGER_TYPE))
     return NULL_TREE;
 
-  if (! host_integerp (len, 1))
+  if (! tree_fits_uhwi_p (len))
     return NULL_TREE;
 
   /* If the LEN parameter is zero, return DEST.  */
@@ -8682,7 +8603,7 @@ fold_builtin_memset (location_t loc, tree dest, tree c, tree len,
   if (! var_decl_component_p (var))
     return NULL_TREE;
 
-  length = tree_low_cst (len, 1);
+  length = tree_to_uhwi (len);
   if (GET_MODE_SIZE (TYPE_MODE (etype)) != length
       || get_pointer_alignment (dest) / BITS_PER_UNIT < length)
     return NULL_TREE;
@@ -8697,7 +8618,7 @@ fold_builtin_memset (location_t loc, tree dest, tree c, tree len,
       if (CHAR_BIT != 8 || BITS_PER_UNIT != 8 || HOST_BITS_PER_WIDE_INT > 64)
 	return NULL_TREE;
 
-      cval = TREE_INT_CST_LOW (c);
+      cval = tree_to_hwi (c);
       cval &= 0xff;
       cval |= cval << 8;
       cval |= cval << 16;
@@ -8785,9 +8706,9 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
 	  if (!dest_align || !src_align)
 	    return NULL_TREE;
 	  if (readonly_data_expr (src)
-	      || (host_integerp (len, 1)
+	      || (tree_fits_uhwi_p (len)
 		  && (MIN (src_align, dest_align) / BITS_PER_UNIT
-		      >= (unsigned HOST_WIDE_INT) tree_low_cst (len, 1))))
+		      >= (unsigned HOST_WIDE_INT) tree_to_uhwi (len))))
 	    {
 	      tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
 	      if (!fn)
@@ -8810,8 +8731,8 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
 	      destvar = TREE_OPERAND (dest, 0);
 	      dest_base = get_ref_base_and_extent (destvar, &dest_offset,
 						   &size, &maxsize);
-	      if (host_integerp (len, 1))
-		maxsize = tree_low_cst (len, 1);
+	      if (tree_fits_uhwi_p (len))
+		maxsize = tree_to_hwi (len);
 	      else
 		maxsize = -1;
 	      src_offset /= BITS_PER_UNIT;
@@ -8827,20 +8748,19 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
 	      else if (TREE_CODE (src_base) == MEM_REF
 		       && TREE_CODE (dest_base) == MEM_REF)
 		{
-		  double_int off;
+		  wide_int off;
 		  if (! operand_equal_p (TREE_OPERAND (src_base, 0),
 					 TREE_OPERAND (dest_base, 0), 0))
 		    return NULL_TREE;
-		  off = mem_ref_offset (src_base) +
-					double_int::from_shwi (src_offset);
-		  if (!off.fits_shwi ())
+		  off = wide_int::from_tree (TREE_OPERAND (src_base, 1)) + src_offset;
+		  if (!off.fits_shwi_p ())
 		    return NULL_TREE;
-		  src_offset = off.low;
-		  off = mem_ref_offset (dest_base) +
-					double_int::from_shwi (dest_offset);
-		  if (!off.fits_shwi ())
+		  src_offset = off.to_shwi ();
+
+		  off = wide_int::from_tree (TREE_OPERAND (dest_base, 1)) + dest_offset;
+		  if (!off.fits_shwi_p ())
 		    return NULL_TREE;
-		  dest_offset = off.low;
+		  dest_offset = off.to_shwi ();
 		  if (ranges_overlap_p (src_offset, maxsize,
 					dest_offset, maxsize))
 		    return NULL_TREE;
@@ -8877,7 +8797,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
 	  return NULL_TREE;
 	}
 
-      if (!host_integerp (len, 0))
+      if (!tree_fits_shwi_p (len))
 	return NULL_TREE;
       /* FIXME:
          This logic lose for arguments like (type *)malloc (sizeof (type)),
@@ -9165,7 +9085,7 @@ fold_builtin_memchr (location_t loc, tree arg1, tree arg2, tree len, tree type)
       const char *p1;
 
       if (TREE_CODE (arg2) != INTEGER_CST
-	  || !host_integerp (len, 1))
+	  || !tree_fits_uhwi_p (len))
 	return NULL_TREE;
 
       p1 = c_getstr (arg1);
@@ -9178,7 +9098,7 @@ fold_builtin_memchr (location_t loc, tree arg1, tree arg2, tree len, tree type)
 	  if (target_char_cast (arg2, &c))
 	    return NULL_TREE;
 
-	  r = (const char *) memchr (p1, c, tree_low_cst (len, 1));
+	  r = (const char *) memchr (p1, c, tree_to_uhwi (len));
 
 	  if (r == NULL)
 	    return build_int_cst (TREE_TYPE (arg1), 0);
@@ -9217,11 +9137,11 @@ fold_builtin_memcmp (location_t loc, tree arg1, tree arg2, tree len)
 
   /* If all arguments are constant, and the value of len is not greater
      than the lengths of arg1 and arg2, evaluate at compile-time.  */
-  if (host_integerp (len, 1) && p1 && p2
+  if (tree_fits_uhwi_p (len) && p1 && p2
       && compare_tree_int (len, strlen (p1) + 1) <= 0
       && compare_tree_int (len, strlen (p2) + 1) <= 0)
     {
-      const int r = memcmp (p1, p2, tree_low_cst (len, 1));
+      const int r = memcmp (p1, p2, tree_to_uhwi (len));
 
       if (r > 0)
 	return integer_one_node;
@@ -9233,7 +9153,7 @@ fold_builtin_memcmp (location_t loc, tree arg1, tree arg2, tree len)
 
   /* If len parameter is one, return an expression corresponding to
      (*(const unsigned char*)arg1 - (const unsigned char*)arg2).  */
-  if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
+  if (tree_fits_uhwi_p (len) && tree_to_hwi (len) == 1)
     {
       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
       tree cst_uchar_ptr_node
@@ -9345,9 +9265,9 @@ fold_builtin_strncmp (location_t loc, tree arg1, tree arg2, tree len)
   p1 = c_getstr (arg1);
   p2 = c_getstr (arg2);
 
-  if (host_integerp (len, 1) && p1 && p2)
+  if (tree_fits_uhwi_p (len) && p1 && p2)
     {
-      const int i = strncmp (p1, p2, tree_low_cst (len, 1));
+      const int i = strncmp (p1, p2, tree_to_hwi (len));
       if (i > 0)
 	return integer_one_node;
       else if (i < 0)
@@ -9393,7 +9313,7 @@ fold_builtin_strncmp (location_t loc, tree arg1, tree arg2, tree len)
 
   /* If len parameter is one, return an expression corresponding to
      (*(const unsigned char*)arg1 - (const unsigned char*)arg2).  */
-  if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
+  if (tree_fits_uhwi_p (len) && tree_to_hwi (len) == 1)
     {
       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
       tree cst_uchar_ptr_node
@@ -9851,7 +9771,7 @@ fold_builtin_load_exponent (location_t loc, tree arg0, tree arg1,
       /* If both arguments are constant, then try to evaluate it.  */
       if ((ldexp || REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2)
 	  && TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)
-	  && host_integerp (arg1, 0))
+	  && tree_fits_shwi_p (arg1))
         {
 	  /* Bound the maximum adjustment to twice the range of the
 	     mode's valid exponents.  Use abs to ensure the range is
@@ -9861,7 +9781,7 @@ fold_builtin_load_exponent (location_t loc, tree arg0, tree arg1,
 		 - REAL_MODE_FORMAT (TYPE_MODE (type))->emin);
 
 	  /* Get the user-requested adjustment.  */
-	  const HOST_WIDE_INT req_exp_adj = tree_low_cst (arg1, 0);
+	  const HOST_WIDE_INT req_exp_adj = tree_to_shwi (arg1);
 
 	  /* The requested adjustment must be inside this range.  This
 	     is a preliminary cap to avoid things like overflow, we
@@ -12331,7 +12251,7 @@ fold_builtin_snprintf (location_t loc, tree dest, tree destsize, tree fmt,
   if (orig && !validate_arg (orig, POINTER_TYPE))
     return NULL_TREE;
 
-  if (!host_integerp (destsize, 1))
+  if (!tree_fits_uhwi_p (destsize))
     return NULL_TREE;
 
   /* Check whether the format is a literal string constant.  */
@@ -12345,7 +12265,7 @@ fold_builtin_snprintf (location_t loc, tree dest, tree destsize, tree fmt,
   if (!init_target_chars ())
     return NULL_TREE;
 
-  destlen = tree_low_cst (destsize, 1);
+  destlen = tree_to_hwi (destsize);
 
   /* If the format doesn't contain % args or %%, use strcpy.  */
   if (strchr (fmt_str, target_percent) == NULL)
@@ -12390,10 +12310,10 @@ fold_builtin_snprintf (location_t loc, tree dest, tree destsize, tree fmt,
 	return NULL_TREE;
 
       retval = c_strlen (orig, 1);
-      if (!retval || !host_integerp (retval, 1))  
+      if (!retval || !tree_fits_uhwi_p (retval))  
 	return NULL_TREE;
 
-      origlen = tree_low_cst (retval, 1);
+      origlen = tree_to_hwi (retval);
       /* We could expand this as
 	 memcpy (str1, str2, cst - 1); str1[cst - 1] = '\0';
 	 or to
@@ -12455,7 +12375,7 @@ expand_builtin_object_size (tree exp)
       return const0_rtx;
     }
 
-  object_size_type = tree_low_cst (ost, 0);
+  object_size_type = tree_to_shwi (ost);
 
   return object_size_type < 2 ? constm1_rtx : const0_rtx;
 }
@@ -12484,10 +12404,10 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
   len = CALL_EXPR_ARG (exp, 2);
   size = CALL_EXPR_ARG (exp, 3);
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_RTX;
 
-  if (host_integerp (len, 1) || integer_all_onesp (size))
+  if (tree_fits_uhwi_p (len) || integer_all_onesp (size))
     {
       tree fn;
 
@@ -12618,22 +12538,22 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
   if (!len || !size)
     return;
 
-  if (! host_integerp (size, 1) || integer_all_onesp (size))
+  if (! tree_fits_uhwi_p (size) || integer_all_onesp (size))
     return;
 
   if (is_strlen)
     {
       len = c_strlen (len, 1);
-      if (! len || ! host_integerp (len, 1) || tree_int_cst_lt (len, size))
+      if (! len || ! tree_fits_uhwi_p (len) || tree_int_cst_lt (len, size))
 	return;
     }
   else if (fcode == BUILT_IN_STRNCAT_CHK)
     {
       tree src = CALL_EXPR_ARG (exp, 1);
-      if (! src || ! host_integerp (len, 1) || tree_int_cst_lt (len, size))
+      if (! src || ! tree_fits_uhwi_p (len) || tree_int_cst_lt (len, size))
 	return;
       src = c_strlen (src, 1);
-      if (! src || ! host_integerp (src, 1))
+      if (! src || ! tree_fits_uhwi_p (src))
 	{
 	  warning_at (loc, 0, "%Kcall to %D might overflow destination buffer",
 		      exp, get_callee_fndecl (exp));
@@ -12642,7 +12562,7 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
       else if (tree_int_cst_lt (src, size))
 	return;
     }
-  else if (! host_integerp (len, 1) || ! tree_int_cst_lt (size, len))
+  else if (! tree_fits_uhwi_p (len) || ! tree_int_cst_lt (size, len))
     return;
 
   warning_at (loc, 0, "%Kcall to %D will always overflow destination buffer",
@@ -12666,7 +12586,7 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
   size = CALL_EXPR_ARG (exp, 2);
   fmt = CALL_EXPR_ARG (exp, 3);
 
-  if (! host_integerp (size, 1) || integer_all_onesp (size))
+  if (! tree_fits_uhwi_p (size) || integer_all_onesp (size))
     return;
 
   /* Check whether the format is a literal string constant.  */
@@ -12694,7 +12614,7 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
 	return;
 
       len = c_strlen (arg, 1);
-      if (!len || ! host_integerp (len, 1))
+      if (!len || ! tree_fits_uhwi_p (len))
 	return;
     }
   else
@@ -12737,6 +12657,7 @@ fold_builtin_object_size (tree ptr, tree ost)
 {
   unsigned HOST_WIDE_INT bytes;
   int object_size_type;
+  int precision = TYPE_PRECISION (TREE_TYPE (ptr));
 
   if (!validate_arg (ptr, POINTER_TYPE)
       || !validate_arg (ost, INTEGER_TYPE))
@@ -12749,7 +12670,7 @@ fold_builtin_object_size (tree ptr, tree ost)
       || compare_tree_int (ost, 3) > 0)
     return NULL_TREE;
 
-  object_size_type = tree_low_cst (ost, 0);
+  object_size_type = tree_to_shwi (ost);
 
   /* __builtin_object_size doesn't evaluate side-effects in its arguments;
      if there are any side-effects, it returns (size_t) -1 for types 0 and 1
@@ -12759,21 +12680,24 @@ fold_builtin_object_size (tree ptr, tree ost)
 
   if (TREE_CODE (ptr) == ADDR_EXPR)
     {
-      bytes = compute_builtin_object_size (ptr, object_size_type);
-      if (double_int_fits_to_tree_p (size_type_node,
-				     double_int::from_uhwi (bytes)))
-	return build_int_cstu (size_type_node, bytes);
+
+      wide_int wbytes 
+	= wide_int::from_uhwi (compute_builtin_object_size (ptr, object_size_type),
+			       precision);
+      if (wbytes.fits_to_tree_p (size_type_node))
+	return wide_int_to_tree (size_type_node, wbytes);
     }
   else if (TREE_CODE (ptr) == SSA_NAME)
     {
       /* If object size is not known yet, delay folding until
        later.  Maybe subsequent passes will help determining
        it.  */
+      wide_int wbytes;
       bytes = compute_builtin_object_size (ptr, object_size_type);
+      wbytes = wide_int::from_uhwi (bytes, precision);
       if (bytes != (unsigned HOST_WIDE_INT) (object_size_type < 2 ? -1 : 0)
-          && double_int_fits_to_tree_p (size_type_node,
-					double_int::from_uhwi (bytes)))
-	return build_int_cstu (size_type_node, bytes);
+          && wbytes.fits_to_tree_p (size_type_node))
+	return wide_int_to_tree (size_type_node, wbytes);
     }
 
   return NULL_TREE;
@@ -12815,17 +12739,17 @@ fold_builtin_memory_chk (location_t loc, tree fndecl,
 	}
     }
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_TREE;
 
   if (! integer_all_onesp (size))
     {
-      if (! host_integerp (len, 1))
+      if (! tree_fits_uhwi_p (len))
 	{
 	  /* If LEN is not constant, try MAXLEN too.
 	     For MAXLEN only allow optimizing into non-_ocs function
 	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
-	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
+	  if (maxlen == NULL_TREE || ! tree_fits_uhwi_p (maxlen))
 	    {
 	      if (fcode == BUILT_IN_MEMPCPY_CHK && ignore)
 		{
@@ -12897,18 +12821,18 @@ fold_builtin_stxcpy_chk (location_t loc, tree fndecl, tree dest,
   if (fcode == BUILT_IN_STRCPY_CHK && operand_equal_p (src, dest, 0))
     return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), dest);
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_TREE;
 
   if (! integer_all_onesp (size))
     {
       len = c_strlen (src, 1);
-      if (! len || ! host_integerp (len, 1))
+      if (! len || ! tree_fits_uhwi_p (len))
 	{
 	  /* If LEN is not constant, try MAXLEN too.
 	     For MAXLEN only allow optimizing into non-_ocs function
 	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
-	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
+	  if (maxlen == NULL_TREE || ! tree_fits_uhwi_p (maxlen))
 	    {
 	      if (fcode == BUILT_IN_STPCPY_CHK)
 		{
@@ -12984,17 +12908,17 @@ fold_builtin_stxncpy_chk (location_t loc, tree dest, tree src,
          return build_call_expr_loc (loc, fn, 4, dest, src, len, size);
     }
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_TREE;
 
   if (! integer_all_onesp (size))
     {
-      if (! host_integerp (len, 1))
+      if (! tree_fits_uhwi_p (len))
 	{
 	  /* If LEN is not constant, try MAXLEN too.
 	     For MAXLEN only allow optimizing into non-_ocs function
 	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
-	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
+	  if (maxlen == NULL_TREE || ! tree_fits_uhwi_p (maxlen))
 	    return NULL_TREE;
 	}
       else
@@ -13033,7 +12957,7 @@ fold_builtin_strcat_chk (location_t loc, tree fndecl, tree dest,
   if (p && *p == '\0')
     return omit_one_operand_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
 
-  if (! host_integerp (size, 1) || ! integer_all_onesp (size))
+  if (! tree_fits_uhwi_p (size) || ! integer_all_onesp (size))
     return NULL_TREE;
 
   /* If __builtin_strcat_chk is used, assume strcat is available.  */
@@ -13067,15 +12991,15 @@ fold_builtin_strncat_chk (location_t loc, tree fndecl,
   else if (integer_zerop (len))
     return omit_one_operand_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_TREE;
 
   if (! integer_all_onesp (size))
     {
       tree src_len = c_strlen (src, 1);
       if (src_len
-	  && host_integerp (src_len, 1)
-	  && host_integerp (len, 1)
+	  && tree_fits_uhwi_p (src_len)
+	  && tree_fits_uhwi_p (len)
 	  && ! tree_int_cst_lt (len, src_len))
 	{
 	  /* If LEN >= strlen (SRC), optimize into __strcat_chk.  */
@@ -13124,7 +13048,7 @@ fold_builtin_sprintf_chk_1 (location_t loc, int nargs, tree *args,
   if (!validate_arg (fmt, POINTER_TYPE))
     return NULL_TREE;
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_TREE;
 
   len = NULL_TREE;
@@ -13155,7 +13079,7 @@ fold_builtin_sprintf_chk_1 (location_t loc, int nargs, tree *args,
 	      if (validate_arg (arg, POINTER_TYPE))
 		{
 		  len = c_strlen (arg, 1);
-		  if (! len || ! host_integerp (len, 1))
+		  if (! len || ! tree_fits_uhwi_p (len))
 		    len = NULL_TREE;
 		}
 	    }
@@ -13232,17 +13156,17 @@ fold_builtin_snprintf_chk_1 (location_t loc, int nargs, tree *args,
   if (!validate_arg (fmt, POINTER_TYPE))
     return NULL_TREE;
 
-  if (! host_integerp (size, 1))
+  if (! tree_fits_uhwi_p (size))
     return NULL_TREE;
 
   if (! integer_all_onesp (size))
     {
-      if (! host_integerp (len, 1))
+      if (! tree_fits_uhwi_p (len))
 	{
 	  /* If LEN is not constant, try MAXLEN too.
 	     For MAXLEN only allow optimizing into non-_ocs function
 	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
-	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
+	  if (maxlen == NULL_TREE || ! tree_fits_uhwi_p (maxlen))
 	    return NULL_TREE;
 	}
       else
@@ -13887,10 +13811,10 @@ do_mpfr_bessel_n (tree arg1, tree arg2, tree type,
   /* To proceed, MPFR must exactly represent the target floating point
      format, which only happens when the target base equals two.  */
   if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
-      && host_integerp (arg1, 0)
+      && tree_fits_shwi_p (arg1)
       && TREE_CODE (arg2) == REAL_CST && !TREE_OVERFLOW (arg2))
     {
-      const HOST_WIDE_INT n = tree_low_cst(arg1, 0);
+      const HOST_WIDE_INT n = tree_to_hwi(arg1);
       const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg2);
 
       if (n == (long)n
diff --git a/gcc/dfp.c b/gcc/dfp.c
index d15ee8f..f0172c1 100644
--- a/gcc/dfp.c
+++ b/gcc/dfp.c
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "tm_p.h"
 #include "dfp.h"
+#include "wide-int.h"
 
 /* The order of the following headers is important for making sure
    decNumber structure is large enough to hold decimal128 digits.  */
@@ -631,6 +632,33 @@ decimal_real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh,
   real_to_integer2 (plow, phigh, &to);
 }
 
+/* Likewise, but returns a wide_int with PRECISION.  Fail
+   is set if the value does not fit.  */
+
+wide_int
+decimal_real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision)
+{
+  decContext set;
+  decNumber dn, dn2, dn3;
+  REAL_VALUE_TYPE to;
+  char string[256];
+
+  decContextDefault (&set, DEC_INIT_DECIMAL128);
+  set.traps = 0;
+  set.round = DEC_ROUND_DOWN;
+  decimal128ToNumber ((const decimal128 *) r->sig, &dn);
+
+  decNumberToIntegralValue (&dn2, &dn, &set);
+  decNumberZero (&dn3);
+  decNumberRescale (&dn, &dn2, &dn3, &set);
+
+  /* Convert to REAL_VALUE_TYPE and call appropriate conversion
+     function.  */
+  decNumberToString (&dn, string);
+  real_from_string (&to, string);
+  return real_to_integer (&to, fail, precision);
+}
+
 /* Perform the decimal floating point operation described by CODE.
    For a unary operation, OP1 will be NULL.  This function returns
    true if the result may be inexact due to loss of precision.  */
diff --git a/gcc/real.c b/gcc/real.c
index b80aeac..976a973 100644
--- a/gcc/real.c
+++ b/gcc/real.c
@@ -29,6 +29,7 @@
 #include "realmpfr.h"
 #include "tm_p.h"
 #include "dfp.h"
+#include "wide-int.h"
 
 /* The floating point model used internally is not exactly IEEE 754
    compliant, and close to the description in the ISO C99 standard,
@@ -1459,6 +1460,91 @@ real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh,
   *phigh = high;
 }
 
+/* Likewise, but producing a wide-int of PRECISION.  If
+   the value cannot be represented in precision, FAIL is set to
+   TRUE.  */
+
+wide_int
+real_to_integer (const REAL_VALUE_TYPE *r, bool *fail, int precision)
+{
+  HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+  int exp;
+  int words;
+  wide_int result;
+  int w;
+
+  switch (r->cl)
+    {
+    case rvc_zero:
+    underflow:
+      return wide_int::zero (precision);
+
+    case rvc_inf:
+    case rvc_nan:
+    overflow:
+      *fail = true;
+      
+      if (r->sign)
+	return wide_int::set_bit_in_zero (precision - 1, precision);
+      else
+	return ~wide_int::set_bit_in_zero (precision - 1, precision);
+
+    case rvc_normal:
+      if (r->decimal)
+	return decimal_real_to_integer (r, fail, precision);
+
+      exp = REAL_EXP (r);
+      if (exp <= 0)
+	goto underflow;
+      /* Only force overflow for unsigned overflow.  Signed overflow is
+	 undefined, so it doesn't matter what we return, and some callers
+	 expect to be able to use this routine for both signed and
+	 unsigned conversions.  */
+      if (exp > precision)
+	goto overflow;
+
+      words = (precision + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT;
+
+      for (int i = 0; i < 2 * MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT; i++)
+	val[i] = 0;
+
+#if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG)
+      for (int i = 0; i < words; i++)
+	{
+	  int j = SIGSZ - words + i;
+	  val[i] = (j < 0) ? 0 : r->sig[j]; 
+	}
+#else
+      gcc_assert (HOST_BITS_PER_WIDE_INT == 2*HOST_BITS_PER_LONG);
+      for (int i = 0; i < words; i++)
+	{
+	  int j = SIGSZ - (words * 2) + (i + 2) + 1;
+	  if (j < 0)
+	    val[i] = 0;
+	  else 
+	    {
+	      val[i] = r->sig[j];
+	      val[i] <<= HOST_BITS_PER_LONG;
+	      val[i] |= r->sig[j - 1];
+	    }
+	}
+#endif 
+      w = SIGSZ * HOST_BITS_PER_LONG + words * HOST_BITS_PER_WIDE_INT; 
+      result = wide_int::from_array (val, 
+	  (w + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT, w, w); 
+      result = result.rshiftu ((words * HOST_BITS_PER_WIDE_INT) - exp);
+      result = result.force_to_size (precision, wide_int::UNSIGNED);
+
+      if (r->sign)
+	return result.neg ();
+      else
+	return result;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* A subroutine of real_to_decimal.  Compute the quotient and remainder
    of NUM / DEN.  Return the quotient and place the remainder in NUM.
    It is expected that NUM / DEN are close enough that the quotient is
diff --git a/gcc/tree.h b/gcc/tree.h
index be43440..2bd4132 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -735,6 +735,8 @@ enum tree_node_structure_enum {
 };
 #undef DEFTREESTRUCT
 
+#define NULL_TREE (tree) NULL
+
 /* Define accessors for the fields that all tree nodes have
    (though some fields are not used for all kinds of nodes).  */
 
@@ -4101,6 +4103,113 @@ omp_clause_elt_check (const_tree __t, int __i,
 
 #endif
 
+/* Return true if T is an INTEGER_CST whose value must be non-negative
+   and can be represented in a single unsigned HOST_WIDE_INT.  */
+
+static inline bool
+tree_fits_uhwi_p (const_tree cst)
+{
+  if (cst == NULL_TREE)
+    return false;
+
+  if (TREE_CODE (cst) != INTEGER_CST)
+    return false;
+
+#ifdef NEW_REP_FOR_INT_CST
+  return TREE_INT_CST_NUNITS (cst) == 1 
+    || (TREE_INT_CST_NUNITS (cst) == 2 && TREE_INT_CST_ELT[1] == 0);
+
+#else
+  return (TREE_INT_CST_HIGH (cst) == 0);
+#endif
+}
+
+/* Return true if CST is an INTEGER_CST whose value can be represented
+   in a single HOST_WIDE_INT.  */
+
+static inline bool
+tree_fits_shwi_p (const_tree cst)
+{
+  if (cst == NULL_TREE)
+    return false;
+
+  if (TREE_CODE (cst) != INTEGER_CST)
+    return false;
+
+#ifdef NEW_REP_FOR_INT_CST
+  return TREE_INT_CST_NUNITS (cst) == 1;
+#else
+  return ((TREE_INT_CST_HIGH (cst) == 0
+	   && (HOST_WIDE_INT) TREE_INT_CST_LOW (cst) >= 0)
+	  || (TREE_INT_CST_HIGH (cst) == -1
+	      && (HOST_WIDE_INT) TREE_INT_CST_LOW (cst) < 0
+	      && !TYPE_UNSIGNED (TREE_TYPE (cst))));
+#endif
+}
+
+/* Return true if T is an INTEGER_CST that can be manipulated
+   efficiently on the host.  If POS is false, the value can be
+   represented in a single HOST_WIDE_INT.  If POS is true, the value
+   must be non-negative and can be represented in a single unsigned
+   HOST_WIDE_INT.  */
+
+static inline bool
+tree_fits_hwi_p (const_tree cst, bool pos)
+{
+  if (cst == NULL_TREE)
+    return 0;
+
+  if (TREE_CODE (cst) != INTEGER_CST)
+    return false;
+
+  return pos ? tree_fits_uhwi_p (cst) : tree_fits_shwi_p (cst);
+}
+
+/* Return the unsigned HOST_WIDE_INT least significant bits of CST.
+   If checking is enabled, this ices if the value does not fit.  */
+
+static inline unsigned HOST_WIDE_INT
+tree_to_uhwi (const_tree cst)
+{
+  gcc_checking_assert (tree_fits_uhwi_p (cst));
+
+#ifdef NEW_REP_FOR_INT_CST
+  return (unsigned HOST_WIDE_INT)TREE_INT_CST_ELT (cst, 0);
+#else
+  return (unsigned HOST_WIDE_INT)TREE_INT_CST_LOW (cst);
+#endif
+}
+
+/* Return the HOST_WIDE_INT least significant bits of CST.  If
+   checking is enabled, this ices if the value does not fit.  */
+
+static inline HOST_WIDE_INT
+tree_to_shwi (const_tree cst)
+{
+  gcc_checking_assert (tree_fits_shwi_p (cst));
+
+#ifdef NEW_REP_FOR_INT_CST
+  return (HOST_WIDE_INT)TREE_INT_CST_ELT (cst, 0);
+#else
+  return (HOST_WIDE_INT)TREE_INT_CST_LOW (cst);
+#endif
+}
+
+/* Return the HOST_WIDE_INT least significant bits of CST.  No
+   checking is done to assure that it fits.  It is assumed that one of
+   tree_fits_uhwi_p or tree_fits_shwi_p was done before this call. */
+
+static inline HOST_WIDE_INT
+tree_to_hwi (const_tree cst)
+{
+#ifdef NEW_REP_FOR_INT_CST
+  return TREE_INT_CST_ELT (cst, 0);
+#else
+  return TREE_INT_CST_LOW (cst);
+#endif
+}
+
+
 /* Compute the number of operands in an expression node NODE.  For
    tcc_vl_exp nodes like CALL_EXPRs, this is stored in the node itself,
    otherwise it is looked up from the node's code.  */
@@ -4568,8 +4677,6 @@ enum ptrmemfunc_vbit_where_t
   ptrmemfunc_vbit_in_delta
 };
 \f
-#define NULL_TREE (tree) NULL
-
 /* True if NODE is an erroneous expression.  */
 
 #define error_operand_p(NODE)					\

[-- Attachment #3: t1-2.clog --]
[-- Type: text/plain, Size: 1316 bytes --]

2012-05-02  Kenneth Zadeck <zadeck@naturalbridge.com>

	* builtins.c (get_object_alignment_2, get_pointer_alignment_1,
	c_strlen, c_getstr, target_char_cast,
	expand_builtin_mempcpy_args, expand_builtin_strncpy,
	expand_builtin_memset_args, expand_builtin_strncpy,
	expand_builtin_memset_args, expand_builtin_frame_address,
	expand_builtin_alloca, expand_builtin_atomic_compare_exchange,
	fold_builtin_powi, fold_builtin_memset,
	fold_builtin_memory_op, fold_builtin_memchr,
	fold_builtin_memcmp, fold_builtin_strncmp,
	fold_builtin_load_exponent, fold_builtin_snprintf,
	expand_builtin_object_size, expand_builtin_memory_chk,
	maybe_emit_chk_warning, maybe_emit_sprintf_chk_warning,
	fold_builtin_object_size, fold_builtin_memory_chk,
	fold_builtin_stxcpy_chk, fold_builtin_strcat_chk,
	fold_builtin_sprintf_chk_1, fold_builtin_snprintf_chk_1,
	do_mpfr_bessel_n): Convert to api that does not assume that
	tree_cst is two HWIs.
	(fold_builtin_int_roundingfn, fold_builtin_bitop,
	fold_builtin_bswap, fold_builtin_memory_op,
	expand_builtin_object_size): Use wide-int rather than double-int api.
	
	* dfp.c (decimal_real_to_integer): Add wide-int version. 
	* real.c (real_to_integer): Ditto.
	* tree.h (tree_fits_uhwi_p, tree_fits_shwi_p, tree_fits_hwi_p, 
	tree_to_shwi, tree_to_hwi, tree_to_uhwi): New functions.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 17:11                                                                                               ` Richard Sandiford
@ 2013-05-03 11:19                                                                                                 ` Richard Biener
  2013-05-03 12:46                                                                                                   ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-05-03 11:19 UTC (permalink / raw)
  To: Richard Biener, Kenneth Zadeck, Mike Stump, gcc-patches,
	Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Wed, Apr 24, 2013 at 5:29 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>> On Wed, Apr 24, 2013 at 4:35 PM, Kenneth Zadeck
>> <zadeck@naturalbridge.com> wrote:
>>> On 04/24/2013 09:36 AM, Richard Biener wrote:
>>>>
>>>> On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford
>>>> <rdsandiford@googlemail.com> wrote:
>>>>>
>>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>>
>>>>>> Can we in such cases please to a preparatory patch and change the
>>>>>> CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
>>>>>> mode precision first?
>>>>>
>>>>> I'm not sure what you mean here.  CONST_INT HWIs are already
>>>>> sign-extended
>>>>> from mode precision to HWI precision.  The 8-bit value 0xb10000000 must
>>>>> be
>>>>> represented as (const_int -128); nothing else is allowed.  E.g.
>>>>> (const_int 128)
>>>>> is not a valid QImode value on BITS_PER_UNIT==8 targets.
>>>>
>>>> Yes, that's what I understand.  But consider you get a CONST_INT that is
>>>> _not_ a valid QImode value.  Current code simply trusts that it is, given
>>>> the context from ...
>>>
>>> And the fact that it we have to trust but cannot verify is a severe problem
>>> at the rtl level that is not going to go away.    what i have been strongly
>>> objecting to is your idea that just because we cannot verify it, we can thus
>>> go change it in some completely different way (i.e. the infinite precision
>>> nonsense that you keep hitting us with) and it will all be ok.
>>
>> Appearantly it is all ok because that's exactly what we have today (and
>> had for the last 25 years).  CONST_INT encodes infinite precision signed
>> values (with the complication that a QImode 0x80 isn't valid, thus all
>> modes are signed as well it seems).
>
> I think this is the fundamental disagreement.  Your last step doesn't
> follow.  RTL integer modes are neither signed nor unsigned.  They are
> just a collection of N bits.  The fact that CONST_INTs represent
> smaller-than-HWI integers in sign-extended form is purely a represential
> detail.  There are no semantics attached to it.  We could just as easily
> have decided to extend with zeros or ones instead of sign bits.
>
> Although the decision was made before my time, I'm pretty sure the
> point of having a canonical representation (which happened to be sign
> extension) was to make sure that any given rtl constant has only a
> single representation.  It would be too confusing if a QImode 0x80 could
> be represented as either (const_int 128) or (const_int -128) (would
> (const_int 384) then also be OK?).

No, not as value for a QImode as it doesn't fit there.

> And that's the problem with using an infinite-precision wide_int.
> If you directly convert a CONST_INT representation of 0x80 into a
> wide_int, you will always get infinite-precision -128, thanks to the
> CONST_INT canonicalisation rule.  But if you arrive at 0x80 though
> arithmetic, you might get infinite-precision 128 instead.  These two
> values would not compare equal.

That's true.  Note that I am not objecting to the canonicalization choice
for the RTL object.  On trees we do have -128 and 128 QImode integers
as tree constants have a sign.

So we clearly cannot have wide_int make that choice, but those that
create either a tree object or a RTL object have to do additional
canonicalization (or truncation to not allow a QImode 384).

Yes, I'm again arguing that making choices for wide_int shouldn't be
done because it seems right for RTL or right for how a CPU operates.
But we are mixing two things in this series of patches - introduction
of an additional RTX object kind CONST_WIDE_INT together with
deciding on its encoding of constant values, and introduction of
a wide_int class as a vehicle to do arithmetic on the host for larger
than HOST_WIDE_INT values.

The latter could be separated by dropping CONST_DOUBLE in favor
of CONST_WIDE_INT everywhere and simply providing a
CONST_WIDE_INT <-> double-int interface (both ways, so you'd
actually never generate a CONST_WIDE_INT that doesn't fit a double-int).

>> CONST_DOUBLE encodes infinite precision signed values as well.  Just
>> the "infinite" is limited by the size of the encoding, one and two
>> HOST_WIDE_INTs.
>
> It encodes an N-bit integer.  It's just that (assuming non-power-of-2
> modes) several N-bit integers (with varying N) can be encoded using the
> same CONST_DOUBLE representation.  That might be what you meant, sorry,
> and so might seem pedantic, but I wasn't sure.

Yes, that's what I meant.  Being able to share the same RTX object for
constants with the same representation but a different mode is nice
and looks appealing (of course works only when the actual mode stored
in the RTX object is then sth like VOIDmode ...).  That we have gazillions
of NULL pointer constants on trees (for each pointer type) isn't.

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-24 18:24                                                                                                       ` Richard Sandiford
@ 2013-05-03 11:28                                                                                                         ` Richard Biener
  2013-05-03 12:38                                                                                                           ` Richard Sandiford
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-05-03 11:28 UTC (permalink / raw)
  To: Richard Biener, Kenneth Zadeck, Mike Stump, gcc-patches,
	Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Wed, Apr 24, 2013 at 5:55 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>> On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford
>> <rdsandiford@googlemail.com> wrote:
>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>> On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
>>>> <rdsandiford@googlemail.com> wrote:
>>>>> In other words, one of the reasons wide_int can't be exactly 1:1
>>>>> in practice is because it is clearing out these mistakes (GEN_INT
>>>>> rather than gen_int_mode) and missing features (non-power-of-2 widths).
>>>>
>>>> Note that the argument should be about CONST_WIDE_INT here,
>>>> not wide-int.  Indeed CONST_WIDE_INT has the desired feature
>>>> and can be properly truncated/extended according to mode at the time
>>>> we build it
>>>> via immed_wide_int_cst (w, mode).  I don't see the requirement that
>>>> wide-int itself is automagically providing that truncation/extension
>>>> (though it is a possibility, one that does not match existing behavior of
>>>> HWI for CONST_INT or double-int for CONST_DOUBLE).
>>>
>>> I agree it doesn't match the existing behaviour of HWI for CONST_INT or
>>> double-int for CONST_DOUBLE, but I think that's very much a good thing.
>>> The model for HWIs at the moment is that you have to truncate results
>>> to the canonical form after every operation where it matters.  As you
>>> proved in your earlier message about the plus_constant bug, that's easily
>>> forgotten.  I don't think the rtl code is doing all CONST_INT arithmetic
>>> on full HWIs because it wants to: it's doing it because that's the way
>>> C/C++ arithmetic on primitive types works.  In other words, the current
>>> CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N)
>>> using a single primitive integer type.  wide_int gives us N-bit arithmetic
>>> directly; no emulation is needed.
>>
>> Ok, so what wide-int provides is integer values encoded in 'len' HWI
>> words that fit in 'precision' or more bits (and often in less).  wide-int
>> also provides N-bit arithmetic operations.  IMHO both are tied
>> too closely together.  A give constant doesn't really have a precision.
>
> I disagree.  All rtl objects have a precision.  REGs, MEMs, SYMBOL_REFs,
> LABEL_REFs and CONSTs all have precisions, and the last three are
> run-time constants.  Why should CONST_INT and CONST_DOUBLE be different?

Well - they _are_ different.  They don't even have a mode at the moment.
If you want to change that be my guest (or well, it's unfortunate to lose
the sharing then) - but Kenny always repeats that this is "impossible to fix".
Having CONST_INT and CONST_DOUBLE without a precision but
CONST_WIDE_INT with a precision would be at least odd.

> See e.g. the hoops that cselib has to jump through:
>
> /* We need to pass down the mode of constants through the hash table
>    functions.  For that purpose, wrap them in a CONST of the appropriate
>    mode.  */
> static rtx
> wrap_constant (enum machine_mode mode, rtx x)
> {
>   if ((!CONST_SCALAR_INT_P (x)) && GET_CODE (x) != CONST_FIXED)
>     return x;
>   gcc_assert (mode != VOIDmode);
>   return gen_rtx_CONST (mode, x);
> }
>
> That is, cselib locally converts (const_int X) into (const:M (const_int X)),
> purely so that it doesn't lose track of the CONST_INT's mode.
> (const:M (const_int ...)) is invalid rtl elsewhere, but a necessary
> hack here all the same.

Indeed ugly.  But I wonder why cselib needs to store constants in
hashtables at all ... they should be VALUEs themselves.  So the fix
for the above might not necessarily be to assign the CONST_INT
a mode (not that CONST_WIDE_INT would fix the above).

>> What RTL currently has looks better to me - operations have
>> explicitely specified precisions.
>
> But that isn't enough to determine the precision of all operands.
> A classic case is ZERO_EXTEND.  Something like:
>
>    (zero_extend:DI (reg:SI X))
>
> is unambiguous.  But if you substitute (reg:SI X) with a CONST_INT,
> the result becomes ambiguous.  E.g. we could end up with:
>
>    (zero_extend:DI (const_int -1))
>
> The ZERO_EXTEND operand still has SImode, but that fact is not explicit
> in the rtl, and is certainly not explicit in the ZERO_EXTEND operation.
> So if we just see the result above, we no longer know whether the result
> should be (const_int 0xff), (const_int 0xffff), or what.  The same goes for:

That situation only occurs when you have "unfolded" RTX.  You should
have never generated the above (and hopefully the RTL verifier doesn't
allow it), but instead called sth like

  simplify_gen_zero_extend (DImode, SImode, x);

with x being the constant substituted for X.  It's probably unfortunate
that parts of the RTL machinery work like (if I remember correctly)
for_each_rtx (x, replace-interesting-stuff); simplify (x);

>    (zero_extend:DI (const_int 256))
>
> where (const_int 0) and (const_int 256) are both potential results.
>
> It's not just ZERO_EXTEND.  E.g.:
>
>   (zero_extract:SI ...)
>
> tells you that an SImode value is being extracted, but it doesn't tell
> you what precision you're extracting from.  So for:
>
>   (zero_extract:SI (const_int -1) (const_int X) (const_int 3))
>
> how many 1 bits should be the result have?  Because of the sign-extension
> canonicalisation, the answer depends on the precision of the (const_int -1),
> which has now been lost.  If instead CONST_INTs were stored in zero-extended
> form, the same ambiguity would apply to SIGN_EXTRACT.
>
> This sort of thing has been a constant headache in rtl.  I can't stress
> how much I feel it is _not_ better than recording the precision of
> the constant :-)

Ok, so please then make all CONST_INTs and CONST_DOUBLEs have
a mode!

The solution is not to have a CONST_WIDE_INT (again with VOIDmode
and no precision in the RTX object(!)) and only have wide_int have a
precision.

So, the proper order to fix things is to get CONST_INTs and CONST_DOUBLEs
to have a mode.  And to make CONST_WIDE_INT inherit that property.

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-04-25  8:38                                                                                                       ` Kenneth Zadeck
@ 2013-05-03 11:34                                                                                                         ` Richard Biener
  2013-05-03 11:50                                                                                                           ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-05-03 11:34 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Thu, Apr 25, 2013 at 1:18 AM, Kenneth Zadeck
<zadeck@naturalbridge.com> wrote:
> On 04/24/2013 11:13 AM, Richard Biener wrote:
>>
>> On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford
>> <rdsandiford@googlemail.com>  wrote:
>>>
>>> Richard Biener<richard.guenther@gmail.com>  writes:
>>>>
>>>> On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
>>>> <rdsandiford@googlemail.com>  wrote:
>>>>>
>>>>> In other words, one of the reasons wide_int can't be exactly 1:1
>>>>> in practice is because it is clearing out these mistakes (GEN_INT
>>>>> rather than gen_int_mode) and missing features (non-power-of-2 widths).
>>>>
>>>> Note that the argument should be about CONST_WIDE_INT here,
>>>> not wide-int.  Indeed CONST_WIDE_INT has the desired feature
>>>> and can be properly truncated/extended according to mode at the time we
>>>> build it
>>>> via immed_wide_int_cst (w, mode).  I don't see the requirement that
>>>> wide-int itself is automagically providing that truncation/extension
>>>> (though it is a possibility, one that does not match existing behavior
>>>> of
>>>> HWI for CONST_INT or double-int for CONST_DOUBLE).
>>>
>>> I agree it doesn't match the existing behaviour of HWI for CONST_INT or
>>> double-int for CONST_DOUBLE, but I think that's very much a good thing.
>>> The model for HWIs at the moment is that you have to truncate results
>>> to the canonical form after every operation where it matters.  As you
>>> proved in your earlier message about the plus_constant bug, that's easily
>>> forgotten.  I don't think the rtl code is doing all CONST_INT arithmetic
>>> on full HWIs because it wants to: it's doing it because that's the way
>>> C/C++ arithmetic on primitive types works.  In other words, the current
>>> CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N)
>>> using a single primitive integer type.  wide_int gives us N-bit
>>> arithmetic
>>> directly; no emulation is needed.
>>
>> Ok, so what wide-int provides is integer values encoded in 'len' HWI
>> words that fit in 'precision' or more bits (and often in less).  wide-int
>> also provides N-bit arithmetic operations.  IMHO both are tied
>> too closely together.  A give constant doesn't really have a precision.
>> Associating one with it to give a precision to an arithmetic operation
>> looks wrong to me and are a source of mismatches.
>>
>> What RTL currently has looks better to me - operations have
>> explicitely specified precisions.
>
> I have tried very hard to make wide-int work very efficiently with both tree
> and rtl without biasing the rep towards either representation.  Both rtl and
> trees constants have a precision.   In tree, constants are done better than
> in rtl because the tree really does have a field that is filled in that
> points to a type. However, that does not mean that rtl constants do not have
> a precision: currently you have to look around at the context to find the
> mode of a constant that is in your hand, but it is in fact always there.
> At the rtl level, you can see the entire patch - we always find an
> appropriate mode.

Appearantly you cannot.  See Richard S. examples.

As of "better", the tree has the issue that we have so many unshared
constants because they only differ in type but not in their representation.
That's the nice part of RTL constants all having VOIDmode ...

Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 11:34                                                                                                         ` Richard Biener
@ 2013-05-03 11:50                                                                                                           ` Kenneth Zadeck
  2013-05-03 12:12                                                                                                             ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-05-03 11:50 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On 05/03/2013 07:34 AM, Richard Biener wrote:
> On Thu, Apr 25, 2013 at 1:18 AM, Kenneth Zadeck
> <zadeck@naturalbridge.com> wrote:
>> On 04/24/2013 11:13 AM, Richard Biener wrote:
>>> On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford
>>> <rdsandiford@googlemail.com>  wrote:
>>>> Richard Biener<richard.guenther@gmail.com>  writes:
>>>>> On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
>>>>> <rdsandiford@googlemail.com>  wrote:
>>>>>> In other words, one of the reasons wide_int can't be exactly 1:1
>>>>>> in practice is because it is clearing out these mistakes (GEN_INT
>>>>>> rather than gen_int_mode) and missing features (non-power-of-2 widths).
>>>>> Note that the argument should be about CONST_WIDE_INT here,
>>>>> not wide-int.  Indeed CONST_WIDE_INT has the desired feature
>>>>> and can be properly truncated/extended according to mode at the time we
>>>>> build it
>>>>> via immed_wide_int_cst (w, mode).  I don't see the requirement that
>>>>> wide-int itself is automagically providing that truncation/extension
>>>>> (though it is a possibility, one that does not match existing behavior
>>>>> of
>>>>> HWI for CONST_INT or double-int for CONST_DOUBLE).
>>>> I agree it doesn't match the existing behaviour of HWI for CONST_INT or
>>>> double-int for CONST_DOUBLE, but I think that's very much a good thing.
>>>> The model for HWIs at the moment is that you have to truncate results
>>>> to the canonical form after every operation where it matters.  As you
>>>> proved in your earlier message about the plus_constant bug, that's easily
>>>> forgotten.  I don't think the rtl code is doing all CONST_INT arithmetic
>>>> on full HWIs because it wants to: it's doing it because that's the way
>>>> C/C++ arithmetic on primitive types works.  In other words, the current
>>>> CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime N)
>>>> using a single primitive integer type.  wide_int gives us N-bit
>>>> arithmetic
>>>> directly; no emulation is needed.
>>> Ok, so what wide-int provides is integer values encoded in 'len' HWI
>>> words that fit in 'precision' or more bits (and often in less).  wide-int
>>> also provides N-bit arithmetic operations.  IMHO both are tied
>>> too closely together.  A give constant doesn't really have a precision.
>>> Associating one with it to give a precision to an arithmetic operation
>>> looks wrong to me and are a source of mismatches.
>>>
>>> What RTL currently has looks better to me - operations have
>>> explicitely specified precisions.
>> I have tried very hard to make wide-int work very efficiently with both tree
>> and rtl without biasing the rep towards either representation.  Both rtl and
>> trees constants have a precision.   In tree, constants are done better than
>> in rtl because the tree really does have a field that is filled in that
>> points to a type. However, that does not mean that rtl constants do not have
>> a precision: currently you have to look around at the context to find the
>> mode of a constant that is in your hand, but it is in fact always there.
>> At the rtl level, you can see the entire patch - we always find an
>> appropriate mode.
> Appearantly you cannot.  See Richard S. examples.
>
> As of "better", the tree has the issue that we have so many unshared
> constants because they only differ in type but not in their representation.
> That's the nice part of RTL constants all having VOIDmode ...
>
> Richard.
I said we could always find a mode, i did not say that in order to find 
the mode we did not have to stand on our head, juggle chainsaws and say 
"mother may i".   The decision to leave the mode as void in rtl integer 
constants was made to save space, but comes with an otherwise very high 
cost and in today's world of cheap memory seems fairly dated.   It is a 
decision that i and others would love to change and the truth is wide 
int is one step in that direction (in that it gets rid of the pun of 
using double-int for both integers and floats where the discriminator is 
voidmode for ints.) But for now we have to live with that poor decision.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 11:50                                                                                                           ` Kenneth Zadeck
@ 2013-05-03 12:12                                                                                                             ` Richard Biener
  2013-05-03 12:31                                                                                                               ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-05-03 12:12 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Fri, May 3, 2013 at 1:49 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> On 05/03/2013 07:34 AM, Richard Biener wrote:
>>
>> On Thu, Apr 25, 2013 at 1:18 AM, Kenneth Zadeck
>> <zadeck@naturalbridge.com> wrote:
>>>
>>> On 04/24/2013 11:13 AM, Richard Biener wrote:
>>>>
>>>> On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford
>>>> <rdsandiford@googlemail.com>  wrote:
>>>>>
>>>>> Richard Biener<richard.guenther@gmail.com>  writes:
>>>>>>
>>>>>> On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
>>>>>> <rdsandiford@googlemail.com>  wrote:
>>>>>>>
>>>>>>> In other words, one of the reasons wide_int can't be exactly 1:1
>>>>>>> in practice is because it is clearing out these mistakes (GEN_INT
>>>>>>> rather than gen_int_mode) and missing features (non-power-of-2
>>>>>>> widths).
>>>>>>
>>>>>> Note that the argument should be about CONST_WIDE_INT here,
>>>>>> not wide-int.  Indeed CONST_WIDE_INT has the desired feature
>>>>>> and can be properly truncated/extended according to mode at the time
>>>>>> we
>>>>>> build it
>>>>>> via immed_wide_int_cst (w, mode).  I don't see the requirement that
>>>>>> wide-int itself is automagically providing that truncation/extension
>>>>>> (though it is a possibility, one that does not match existing behavior
>>>>>> of
>>>>>> HWI for CONST_INT or double-int for CONST_DOUBLE).
>>>>>
>>>>> I agree it doesn't match the existing behaviour of HWI for CONST_INT or
>>>>> double-int for CONST_DOUBLE, but I think that's very much a good thing.
>>>>> The model for HWIs at the moment is that you have to truncate results
>>>>> to the canonical form after every operation where it matters.  As you
>>>>> proved in your earlier message about the plus_constant bug, that's
>>>>> easily
>>>>> forgotten.  I don't think the rtl code is doing all CONST_INT
>>>>> arithmetic
>>>>> on full HWIs because it wants to: it's doing it because that's the way
>>>>> C/C++ arithmetic on primitive types works.  In other words, the current
>>>>> CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime
>>>>> N)
>>>>> using a single primitive integer type.  wide_int gives us N-bit
>>>>> arithmetic
>>>>> directly; no emulation is needed.
>>>>
>>>> Ok, so what wide-int provides is integer values encoded in 'len' HWI
>>>> words that fit in 'precision' or more bits (and often in less).
>>>> wide-int
>>>> also provides N-bit arithmetic operations.  IMHO both are tied
>>>> too closely together.  A give constant doesn't really have a precision.
>>>> Associating one with it to give a precision to an arithmetic operation
>>>> looks wrong to me and are a source of mismatches.
>>>>
>>>> What RTL currently has looks better to me - operations have
>>>> explicitely specified precisions.
>>>
>>> I have tried very hard to make wide-int work very efficiently with both
>>> tree
>>> and rtl without biasing the rep towards either representation.  Both rtl
>>> and
>>> trees constants have a precision.   In tree, constants are done better
>>> than
>>> in rtl because the tree really does have a field that is filled in that
>>> points to a type. However, that does not mean that rtl constants do not
>>> have
>>> a precision: currently you have to look around at the context to find the
>>> mode of a constant that is in your hand, but it is in fact always there.
>>> At the rtl level, you can see the entire patch - we always find an
>>> appropriate mode.
>>
>> Appearantly you cannot.  See Richard S. examples.
>>
>> As of "better", the tree has the issue that we have so many unshared
>> constants because they only differ in type but not in their
>> representation.
>> That's the nice part of RTL constants all having VOIDmode ...
>>
>> Richard.
>
> I said we could always find a mode, i did not say that in order to find the
> mode we did not have to stand on our head, juggle chainsaws and say "mother
> may i".   The decision to leave the mode as void in rtl integer constants
> was made to save space, but comes with an otherwise very high cost and in
> today's world of cheap memory seems fairly dated.   It is a decision that i
> and others would love to change and the truth is wide int is one step in
> that direction (in that it gets rid of the pun of using double-int for both
> integers and floats where the discriminator is voidmode for ints.) But for
> now we have to live with that poor decision.

As far as I have read your wide-int patches the CONST_WIDE_INT RTX
object does not include a mode.  So I don't see it as a step forward in
any way (other than that it makes it explicit that you _do_ need a mode
to do any operation on a constant).

Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 12:12                                                                                                             ` Richard Biener
@ 2013-05-03 12:31                                                                                                               ` Kenneth Zadeck
  2013-05-03 12:40                                                                                                                 ` Richard Biener
  2013-05-03 12:48                                                                                                                 ` Richard Sandiford
  0 siblings, 2 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-05-03 12:31 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On 05/03/2013 08:12 AM, Richard Biener wrote:
> On Fri, May 3, 2013 at 1:49 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> On 05/03/2013 07:34 AM, Richard Biener wrote:
>>> On Thu, Apr 25, 2013 at 1:18 AM, Kenneth Zadeck
>>> <zadeck@naturalbridge.com> wrote:
>>>> On 04/24/2013 11:13 AM, Richard Biener wrote:
>>>>> On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford
>>>>> <rdsandiford@googlemail.com>  wrote:
>>>>>> Richard Biener<richard.guenther@gmail.com>  writes:
>>>>>>> On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
>>>>>>> <rdsandiford@googlemail.com>  wrote:
>>>>>>>> In other words, one of the reasons wide_int can't be exactly 1:1
>>>>>>>> in practice is because it is clearing out these mistakes (GEN_INT
>>>>>>>> rather than gen_int_mode) and missing features (non-power-of-2
>>>>>>>> widths).
>>>>>>> Note that the argument should be about CONST_WIDE_INT here,
>>>>>>> not wide-int.  Indeed CONST_WIDE_INT has the desired feature
>>>>>>> and can be properly truncated/extended according to mode at the time
>>>>>>> we
>>>>>>> build it
>>>>>>> via immed_wide_int_cst (w, mode).  I don't see the requirement that
>>>>>>> wide-int itself is automagically providing that truncation/extension
>>>>>>> (though it is a possibility, one that does not match existing behavior
>>>>>>> of
>>>>>>> HWI for CONST_INT or double-int for CONST_DOUBLE).
>>>>>> I agree it doesn't match the existing behaviour of HWI for CONST_INT or
>>>>>> double-int for CONST_DOUBLE, but I think that's very much a good thing.
>>>>>> The model for HWIs at the moment is that you have to truncate results
>>>>>> to the canonical form after every operation where it matters.  As you
>>>>>> proved in your earlier message about the plus_constant bug, that's
>>>>>> easily
>>>>>> forgotten.  I don't think the rtl code is doing all CONST_INT
>>>>>> arithmetic
>>>>>> on full HWIs because it wants to: it's doing it because that's the way
>>>>>> C/C++ arithmetic on primitive types works.  In other words, the current
>>>>>> CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime
>>>>>> N)
>>>>>> using a single primitive integer type.  wide_int gives us N-bit
>>>>>> arithmetic
>>>>>> directly; no emulation is needed.
>>>>> Ok, so what wide-int provides is integer values encoded in 'len' HWI
>>>>> words that fit in 'precision' or more bits (and often in less).
>>>>> wide-int
>>>>> also provides N-bit arithmetic operations.  IMHO both are tied
>>>>> too closely together.  A give constant doesn't really have a precision.
>>>>> Associating one with it to give a precision to an arithmetic operation
>>>>> looks wrong to me and are a source of mismatches.
>>>>>
>>>>> What RTL currently has looks better to me - operations have
>>>>> explicitely specified precisions.
>>>> I have tried very hard to make wide-int work very efficiently with both
>>>> tree
>>>> and rtl without biasing the rep towards either representation.  Both rtl
>>>> and
>>>> trees constants have a precision.   In tree, constants are done better
>>>> than
>>>> in rtl because the tree really does have a field that is filled in that
>>>> points to a type. However, that does not mean that rtl constants do not
>>>> have
>>>> a precision: currently you have to look around at the context to find the
>>>> mode of a constant that is in your hand, but it is in fact always there.
>>>> At the rtl level, you can see the entire patch - we always find an
>>>> appropriate mode.
>>> Appearantly you cannot.  See Richard S. examples.
>>>
>>> As of "better", the tree has the issue that we have so many unshared
>>> constants because they only differ in type but not in their
>>> representation.
>>> That's the nice part of RTL constants all having VOIDmode ...
>>>
>>> Richard.
>> I said we could always find a mode, i did not say that in order to find the
>> mode we did not have to stand on our head, juggle chainsaws and say "mother
>> may i".   The decision to leave the mode as void in rtl integer constants
>> was made to save space, but comes with an otherwise very high cost and in
>> today's world of cheap memory seems fairly dated.   It is a decision that i
>> and others would love to change and the truth is wide int is one step in
>> that direction (in that it gets rid of the pun of using double-int for both
>> integers and floats where the discriminator is voidmode for ints.) But for
>> now we have to live with that poor decision.
> As far as I have read your wide-int patches the CONST_WIDE_INT RTX
> object does not include a mode.  So I don't see it as a step forward in
> any way (other than that it makes it explicit that you _do_ need a mode
> to do any operation on a constant).
>
> Richard.
There are several problems with just dropping a mode into the already 
existing mode field of an rtx constant.
1) There may be places where the a back end is testing equality to see 
if constants of different modes are in fact the same value.
2) Most of the places what build int constants use GEN_INT which does 
not take a mode, even though about 95% of those places have a mode right 
there and the rest just take a little work.    There are constructor 
that do take a mode, but in the end they just throw the mode on the floor.
3) The canonical test to see if a CONST_DOUBLE contains an int or float 
is to test if the mode is VOIDmode.

Any port that is converted to have TARGET_SUPPORTS_WIDE_INT has no more 
of problem (3).   I admit that rooting out (1) is likely to be the worst 
of the problems.   But we were careful to at least make this work move 
us in the correct direction.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 11:28                                                                                                         ` Richard Biener
@ 2013-05-03 12:38                                                                                                           ` Richard Sandiford
  2013-05-03 12:53                                                                                                             ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2013-05-03 12:38 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Richard Biener <richard.guenther@gmail.com> writes:
>> See e.g. the hoops that cselib has to jump through:
>>
>> /* We need to pass down the mode of constants through the hash table
>>    functions.  For that purpose, wrap them in a CONST of the appropriate
>>    mode.  */
>> static rtx
>> wrap_constant (enum machine_mode mode, rtx x)
>> {
>>   if ((!CONST_SCALAR_INT_P (x)) && GET_CODE (x) != CONST_FIXED)
>>     return x;
>>   gcc_assert (mode != VOIDmode);
>>   return gen_rtx_CONST (mode, x);
>> }
>>
>> That is, cselib locally converts (const_int X) into (const:M (const_int X)),
>> purely so that it doesn't lose track of the CONST_INT's mode.
>> (const:M (const_int ...)) is invalid rtl elsewhere, but a necessary
>> hack here all the same.
>
> Indeed ugly.  But I wonder why cselib needs to store constants in
> hashtables at all ... they should be VALUEs themselves.  So the fix
> for the above might not necessarily be to assign the CONST_INT
> a mode (not that CONST_WIDE_INT would fix the above).

I don't understand.  Do you mean that cselib values ought to have
a field to say whether the value is constant or not, and if so, what
constant that is?  That feels like just the same kind of hack as the above.
The current idea of chaining all known equivalent rtxes in a list seems
more natural than having a list of all known equivalent rtxes except
CONST_INT and CONST_DOUBLE, which have to be stored separately instead.
(Again, we have runtime constants like SYMBOL_REF, which store modes,
and which would presumably still be in the normal rtx list.)

CONST_WIDE_INT was never supposed to solve this problem.  I'm just giving
it as an example to back up the argument that rtx constants do in fact
have modes (although those modes are not stored in the rtx).  The code
above is there to make sure that equivalence stays transitive.
Without it we could have bogus equivalences like:

  (A) (reg:DI X) == (const_int Y) == (reg:SI Z)

even though it cannot be the case that:

  (B) (reg:DI X) == (reg:SI Z)

My point is that, semantically, (A) did not come from X and Z being
equivalent to the "same" constant.  X was equivalent to (const_int:DI Y)
and Z was equivalent to (const_int:SI Y).  (A) only came about because
we happen to use the same rtx object to represent those two semantically-
distinct constants.

The idea isn't to make CONST_WIDE_INT get rid of the code above.
The idea is to make sure that wide_int has a precision and so doesn't
require code like the above to be written when dealing with wide_ints.

In other words, I got the impression your argument was "the fact
that CONST_INT and CONST_DOUBLE don't store a mode shows that
wide_int shouldn't store a precision".  But the fact that CONST_INT
and CONST_DOUBLE don't store a mode doesn't mean they don't _have_
a mode.  You just have to keep track of that mode separately.
And the same would apply to wide_int if we did the same thing there.

What I was trying to argue was that storing the mode/precision
separately is not always easy.  It's also much less robust,
because getting the wrong mode or precision will only show up
for certain values.  If the precision is stored in the wide_int,
mismatches can be asserted for based on precision alone, regardless
of the value.

> Ok, so please then make all CONST_INTs and CONST_DOUBLEs have
> a mode!

I'm saying that CONST_INT and CONST_DOUBLE already have a mode, but that
mode is not stored in the rtx.  So if you're saying "make all CONST_INTs
and CONST_DOUBLEs _store_ a mode", then yeah, I'd like to :-)  But I see
Kenny's patch as a prerequisite for that, because it consolidates the
CONST_INT and CONST_DOUBLE code so that the choice of rtx code is
less special.  Lots more work is needed after that.

Although TBH, the huge pushback that Kenny has got from this patch
puts me off ever trying that change.

But storing the mode in the rtx is orthogonal to what Kenny is doing.
The mode of each rtx constant is already available in the places
that Kenny is changing, because we already do the work to keep track
of the mode separately.  Being able to get the mode directly from the
rtx would be simpler and IMO better, but the semantics are the same
either way.

Kenny's patch is not designed to "fix" the CONST_INT representation
(although the patch does make it easier to "fix" the representation
in future).  Kenny's patch is about representing and handling constants
that we can't at the moment.

The argument isn't whether CONST_WIDE_INT repeats "mistakes" made for
CONST_INT and CONST_DOUBLE; I hope we agree that CONST_WIDE_INT should
behave like the other two, whatever that is.  The argument is about
whether we copy the "mistake" into the wide_int class.

Storing a precision in wide_int in no way requires CONST_WIDE_INT
to store a mode.  They are separate choices.

> The solution is not to have a CONST_WIDE_INT (again with VOIDmode
> and no precision in the RTX object(!)) and only have wide_int have a
> precision.

Why is having a VOIDmode CONST_WIDE_INT any worse than having
a VOIDmode CONST_INT or CONST_DOUBLE?  In all three cases the mode
is being obtained/inferred from the same external source.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 12:31                                                                                                               ` Kenneth Zadeck
@ 2013-05-03 12:40                                                                                                                 ` Richard Biener
  2013-05-03 14:09                                                                                                                   ` Kenneth Zadeck
  2013-05-03 12:48                                                                                                                 ` Richard Sandiford
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-05-03 12:40 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Fri, May 3, 2013 at 2:31 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> On 05/03/2013 08:12 AM, Richard Biener wrote:
>>
>> On Fri, May 3, 2013 at 1:49 PM, Kenneth Zadeck <zadeck@naturalbridge.com>
>> wrote:
>>>
>>> On 05/03/2013 07:34 AM, Richard Biener wrote:
>>>>
>>>> On Thu, Apr 25, 2013 at 1:18 AM, Kenneth Zadeck
>>>> <zadeck@naturalbridge.com> wrote:
>>>>>
>>>>> On 04/24/2013 11:13 AM, Richard Biener wrote:
>>>>>>
>>>>>> On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford
>>>>>> <rdsandiford@googlemail.com>  wrote:
>>>>>>>
>>>>>>> Richard Biener<richard.guenther@gmail.com>  writes:
>>>>>>>>
>>>>>>>> On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
>>>>>>>> <rdsandiford@googlemail.com>  wrote:
>>>>>>>>>
>>>>>>>>> In other words, one of the reasons wide_int can't be exactly 1:1
>>>>>>>>> in practice is because it is clearing out these mistakes (GEN_INT
>>>>>>>>> rather than gen_int_mode) and missing features (non-power-of-2
>>>>>>>>> widths).
>>>>>>>>
>>>>>>>> Note that the argument should be about CONST_WIDE_INT here,
>>>>>>>> not wide-int.  Indeed CONST_WIDE_INT has the desired feature
>>>>>>>> and can be properly truncated/extended according to mode at the time
>>>>>>>> we
>>>>>>>> build it
>>>>>>>> via immed_wide_int_cst (w, mode).  I don't see the requirement that
>>>>>>>> wide-int itself is automagically providing that truncation/extension
>>>>>>>> (though it is a possibility, one that does not match existing
>>>>>>>> behavior
>>>>>>>> of
>>>>>>>> HWI for CONST_INT or double-int for CONST_DOUBLE).
>>>>>>>
>>>>>>> I agree it doesn't match the existing behaviour of HWI for CONST_INT
>>>>>>> or
>>>>>>> double-int for CONST_DOUBLE, but I think that's very much a good
>>>>>>> thing.
>>>>>>> The model for HWIs at the moment is that you have to truncate results
>>>>>>> to the canonical form after every operation where it matters.  As you
>>>>>>> proved in your earlier message about the plus_constant bug, that's
>>>>>>> easily
>>>>>>> forgotten.  I don't think the rtl code is doing all CONST_INT
>>>>>>> arithmetic
>>>>>>> on full HWIs because it wants to: it's doing it because that's the
>>>>>>> way
>>>>>>> C/C++ arithmetic on primitive types works.  In other words, the
>>>>>>> current
>>>>>>> CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime
>>>>>>> N)
>>>>>>> using a single primitive integer type.  wide_int gives us N-bit
>>>>>>> arithmetic
>>>>>>> directly; no emulation is needed.
>>>>>>
>>>>>> Ok, so what wide-int provides is integer values encoded in 'len' HWI
>>>>>> words that fit in 'precision' or more bits (and often in less).
>>>>>> wide-int
>>>>>> also provides N-bit arithmetic operations.  IMHO both are tied
>>>>>> too closely together.  A give constant doesn't really have a
>>>>>> precision.
>>>>>> Associating one with it to give a precision to an arithmetic operation
>>>>>> looks wrong to me and are a source of mismatches.
>>>>>>
>>>>>> What RTL currently has looks better to me - operations have
>>>>>> explicitely specified precisions.
>>>>>
>>>>> I have tried very hard to make wide-int work very efficiently with both
>>>>> tree
>>>>> and rtl without biasing the rep towards either representation.  Both
>>>>> rtl
>>>>> and
>>>>> trees constants have a precision.   In tree, constants are done better
>>>>> than
>>>>> in rtl because the tree really does have a field that is filled in that
>>>>> points to a type. However, that does not mean that rtl constants do not
>>>>> have
>>>>> a precision: currently you have to look around at the context to find
>>>>> the
>>>>> mode of a constant that is in your hand, but it is in fact always
>>>>> there.
>>>>> At the rtl level, you can see the entire patch - we always find an
>>>>> appropriate mode.
>>>>
>>>> Appearantly you cannot.  See Richard S. examples.
>>>>
>>>> As of "better", the tree has the issue that we have so many unshared
>>>> constants because they only differ in type but not in their
>>>> representation.
>>>> That's the nice part of RTL constants all having VOIDmode ...
>>>>
>>>> Richard.
>>>
>>> I said we could always find a mode, i did not say that in order to find
>>> the
>>> mode we did not have to stand on our head, juggle chainsaws and say
>>> "mother
>>> may i".   The decision to leave the mode as void in rtl integer constants
>>> was made to save space, but comes with an otherwise very high cost and in
>>> today's world of cheap memory seems fairly dated.   It is a decision that
>>> i
>>> and others would love to change and the truth is wide int is one step in
>>> that direction (in that it gets rid of the pun of using double-int for
>>> both
>>> integers and floats where the discriminator is voidmode for ints.) But
>>> for
>>> now we have to live with that poor decision.
>>
>> As far as I have read your wide-int patches the CONST_WIDE_INT RTX
>> object does not include a mode.  So I don't see it as a step forward in
>> any way (other than that it makes it explicit that you _do_ need a mode
>> to do any operation on a constant).
>>
>> Richard.
>
> There are several problems with just dropping a mode into the already
> existing mode field of an rtx constant.
> 1) There may be places where the a back end is testing equality to see if
> constants of different modes are in fact the same value.

That supposedly only happens in places where both RTX objects are
know to be constants.  Which makes me guess that it's in 99% of the
cases a comparison against one of the static RTX objects like
const0_rtx - thus easily greppable for (and easily converted similar
to the tree case where we have predicates for such tests like integer_zerop ()).
The remaining cases would be missed optimizations at most.

> 2) Most of the places what build int constants use GEN_INT which does not
> take a mode, even though about 95% of those places have a mode right there
> and the rest just take a little work.    There are constructor that do take
> a mode, but in the end they just throw the mode on the floor.

The fix is easy - make GEN_INT take a mandatory mode argument.
(and fix the fallout ...)

> 3) The canonical test to see if a CONST_DOUBLE contains an int or float is
> to test if the mode is VOIDmode.

I think you addressed this already by introducing CONST_DOUBLE_AS_INT_P ().

> Any port that is converted to have TARGET_SUPPORTS_WIDE_INT has no more of
> problem (3).   I admit that rooting out (1) is likely to be the worst of the
> problems.   But we were careful to at least make this work move us in the
> correct direction.

Well, you were careful to not walk in the wrong direction.  But I cannot see
were you get closer to fix any of 1-3 (apart from considering the new predicates
being that, or not overloading CONST_DOUBLE with floats and ints).

Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 11:19                                                                                                 ` Richard Biener
@ 2013-05-03 12:46                                                                                                   ` Kenneth Zadeck
  2013-05-03 13:02                                                                                                     ` Richard Biener
  0 siblings, 1 reply; 217+ messages in thread
From: Kenneth Zadeck @ 2013-05-03 12:46 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On 05/03/2013 07:19 AM, Richard Biener wrote:
> On Wed, Apr 24, 2013 at 5:29 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>> On Wed, Apr 24, 2013 at 4:35 PM, Kenneth Zadeck
>>> <zadeck@naturalbridge.com> wrote:
>>>> On 04/24/2013 09:36 AM, Richard Biener wrote:
>>>>> On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford
>>>>> <rdsandiford@googlemail.com> wrote:
>>>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>>> Can we in such cases please to a preparatory patch and change the
>>>>>>> CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
>>>>>>> mode precision first?
>>>>>> I'm not sure what you mean here.  CONST_INT HWIs are already
>>>>>> sign-extended
>>>>>> from mode precision to HWI precision.  The 8-bit value 0xb10000000 must
>>>>>> be
>>>>>> represented as (const_int -128); nothing else is allowed.  E.g.
>>>>>> (const_int 128)
>>>>>> is not a valid QImode value on BITS_PER_UNIT==8 targets.
>>>>> Yes, that's what I understand.  But consider you get a CONST_INT that is
>>>>> _not_ a valid QImode value.  Current code simply trusts that it is, given
>>>>> the context from ...
>>>> And the fact that it we have to trust but cannot verify is a severe problem
>>>> at the rtl level that is not going to go away.    what i have been strongly
>>>> objecting to is your idea that just because we cannot verify it, we can thus
>>>> go change it in some completely different way (i.e. the infinite precision
>>>> nonsense that you keep hitting us with) and it will all be ok.
>>> Appearantly it is all ok because that's exactly what we have today (and
>>> had for the last 25 years).  CONST_INT encodes infinite precision signed
>>> values (with the complication that a QImode 0x80 isn't valid, thus all
>>> modes are signed as well it seems).
>> I think this is the fundamental disagreement.  Your last step doesn't
>> follow.  RTL integer modes are neither signed nor unsigned.  They are
>> just a collection of N bits.  The fact that CONST_INTs represent
>> smaller-than-HWI integers in sign-extended form is purely a represential
>> detail.  There are no semantics attached to it.  We could just as easily
>> have decided to extend with zeros or ones instead of sign bits.
>>
>> Although the decision was made before my time, I'm pretty sure the
>> point of having a canonical representation (which happened to be sign
>> extension) was to make sure that any given rtl constant has only a
>> single representation.  It would be too confusing if a QImode 0x80 could
>> be represented as either (const_int 128) or (const_int -128) (would
>> (const_int 384) then also be OK?).
> No, not as value for a QImode as it doesn't fit there.
>
>> And that's the problem with using an infinite-precision wide_int.
>> If you directly convert a CONST_INT representation of 0x80 into a
>> wide_int, you will always get infinite-precision -128, thanks to the
>> CONST_INT canonicalisation rule.  But if you arrive at 0x80 though
>> arithmetic, you might get infinite-precision 128 instead.  These two
>> values would not compare equal.
> That's true.  Note that I am not objecting to the canonicalization choice
> for the RTL object.  On trees we do have -128 and 128 QImode integers
> as tree constants have a sign.
>
> So we clearly cannot have wide_int make that choice, but those that
> create either a tree object or a RTL object have to do additional
> canonicalization (or truncation to not allow a QImode 384).
>
> Yes, I'm again arguing that making choices for wide_int shouldn't be
> done because it seems right for RTL or right for how a CPU operates.
> But we are mixing two things in this series of patches - introduction
> of an additional RTX object kind CONST_WIDE_INT together with
> deciding on its encoding of constant values, and introduction of
> a wide_int class as a vehicle to do arithmetic on the host for larger
> than HOST_WIDE_INT values.
>
> The latter could be separated by dropping CONST_DOUBLE in favor
> of CONST_WIDE_INT everywhere and simply providing a
> CONST_WIDE_INT <-> double-int interface (both ways, so you'd
> actually never generate a CONST_WIDE_INT that doesn't fit a double-int).
Given the tree world, i am surprised that you would push in this 
direction.   While i do see some benefit for having two reps for ints at 
the rtl level, I understand the argument that is one too many.

The target_supports_wide_int is a transitional trick.   The idea is to 
move the ports away from using CONST_DOUBLE at all for ints. Not only is 
this a step towards putting a mode in an rtl int const, but it also 
would allow the floating point world to move beyond the limits that 
sharing the rep with integers imposes.

One of the big goals of this cleanup is to get rid of the three path 
implementation for integer math:
constant fits in HWI - good implementation.
constant fits in 2 HWIs - spotty implementation.
constant needs more than 2 HWIs - ice or get wrong answer.

Doing a trick like this just makes it harder to unify everything into 
the good implementation category.

>
>>> CONST_DOUBLE encodes infinite precision signed values as well.  Just
>>> the "infinite" is limited by the size of the encoding, one and two
>>> HOST_WIDE_INTs.
>> It encodes an N-bit integer.  It's just that (assuming non-power-of-2
>> modes) several N-bit integers (with varying N) can be encoded using the
>> same CONST_DOUBLE representation.  That might be what you meant, sorry,
>> and so might seem pedantic, but I wasn't sure.
> Yes, that's what I meant.  Being able to share the same RTX object for
> constants with the same representation but a different mode is nice
> and looks appealing (of course works only when the actual mode stored
> in the RTX object is then sth like VOIDmode ...).  That we have gazillions
> of NULL pointer constants on trees (for each pointer type) isn't.
>
> Richard.
4 gb of memory is less than $30US.   We need to move on.   The pain that 
no mode causes is significant.
>
>> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 12:31                                                                                                               ` Kenneth Zadeck
  2013-05-03 12:40                                                                                                                 ` Richard Biener
@ 2013-05-03 12:48                                                                                                                 ` Richard Sandiford
  2013-05-03 13:06                                                                                                                   ` Richard Biener
  1 sibling, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2013-05-03 12:48 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Kenneth Zadeck <zadeck@naturalbridge.com> writes:
> There are several problems with just dropping a mode into the already 
> existing mode field of an rtx constant.
> 1) There may be places where the a back end is testing equality to see 
> if constants of different modes are in fact the same value.
> 2) Most of the places what build int constants use GEN_INT which does 
> not take a mode, even though about 95% of those places have a mode right 
> there and the rest just take a little work.    There are constructor 
> that do take a mode, but in the end they just throw the mode on the floor.
> 3) The canonical test to see if a CONST_DOUBLE contains an int or float 
> is to test if the mode is VOIDmode.
>
> Any port that is converted to have TARGET_SUPPORTS_WIDE_INT has no more 
> of problem (3).   I admit that rooting out (1) is likely to be the worst 
> of the problems.   But we were careful to at least make this work move 
> us in the correct direction.

I agree with that, and FWIW, there are others.  Two off the top of my head:

4) Many places use const0_rtx instead of CONST0_RTX (mode) (correctly,
   according to current representation)
5) All const_ints in the .md files would need to be given a mode
   (except for those places where const_int actually represents
   a C++ constant, such as in attributes).

I realise your list wasn't supposed to be exhaustive, and neither's mine :-)

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 12:38                                                                                                           ` Richard Sandiford
@ 2013-05-03 12:53                                                                                                             ` Richard Biener
  2013-05-03 13:50                                                                                                               ` Richard Sandiford
  2013-05-03 14:27                                                                                                               ` Kenneth Zadeck
  0 siblings, 2 replies; 217+ messages in thread
From: Richard Biener @ 2013-05-03 12:53 UTC (permalink / raw)
  To: Richard Biener, Kenneth Zadeck, Mike Stump, gcc-patches,
	Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Fri, May 3, 2013 at 2:37 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>>> See e.g. the hoops that cselib has to jump through:
>>>
>>> /* We need to pass down the mode of constants through the hash table
>>>    functions.  For that purpose, wrap them in a CONST of the appropriate
>>>    mode.  */
>>> static rtx
>>> wrap_constant (enum machine_mode mode, rtx x)
>>> {
>>>   if ((!CONST_SCALAR_INT_P (x)) && GET_CODE (x) != CONST_FIXED)
>>>     return x;
>>>   gcc_assert (mode != VOIDmode);
>>>   return gen_rtx_CONST (mode, x);
>>> }
>>>
>>> That is, cselib locally converts (const_int X) into (const:M (const_int X)),
>>> purely so that it doesn't lose track of the CONST_INT's mode.
>>> (const:M (const_int ...)) is invalid rtl elsewhere, but a necessary
>>> hack here all the same.
>>
>> Indeed ugly.  But I wonder why cselib needs to store constants in
>> hashtables at all ... they should be VALUEs themselves.  So the fix
>> for the above might not necessarily be to assign the CONST_INT
>> a mode (not that CONST_WIDE_INT would fix the above).
>
> I don't understand.  Do you mean that cselib values ought to have
> a field to say whether the value is constant or not, and if so, what
> constant that is?  That feels like just the same kind of hack as the above.
> The current idea of chaining all known equivalent rtxes in a list seems
> more natural than having a list of all known equivalent rtxes except
> CONST_INT and CONST_DOUBLE, which have to be stored separately instead.
> (Again, we have runtime constants like SYMBOL_REF, which store modes,
> and which would presumably still be in the normal rtx list.)
>
> CONST_WIDE_INT was never supposed to solve this problem.  I'm just giving
> it as an example to back up the argument that rtx constants do in fact
> have modes (although those modes are not stored in the rtx).  The code
> above is there to make sure that equivalence stays transitive.
> Without it we could have bogus equivalences like:
>
>   (A) (reg:DI X) == (const_int Y) == (reg:SI Z)
>
> even though it cannot be the case that:
>
>   (B) (reg:DI X) == (reg:SI Z)
>
> My point is that, semantically, (A) did not come from X and Z being
> equivalent to the "same" constant.  X was equivalent to (const_int:DI Y)
> and Z was equivalent to (const_int:SI Y).  (A) only came about because
> we happen to use the same rtx object to represent those two semantically-
> distinct constants.
>
> The idea isn't to make CONST_WIDE_INT get rid of the code above.
> The idea is to make sure that wide_int has a precision and so doesn't
> require code like the above to be written when dealing with wide_ints.
>
> In other words, I got the impression your argument was "the fact
> that CONST_INT and CONST_DOUBLE don't store a mode shows that
> wide_int shouldn't store a precision".  But the fact that CONST_INT
> and CONST_DOUBLE don't store a mode doesn't mean they don't _have_
> a mode.  You just have to keep track of that mode separately.
> And the same would apply to wide_int if we did the same thing there.
>
> What I was trying to argue was that storing the mode/precision
> separately is not always easy.  It's also much less robust,
> because getting the wrong mode or precision will only show up
> for certain values.  If the precision is stored in the wide_int,
> mismatches can be asserted for based on precision alone, regardless
> of the value.

I was just arguing that pointing out facts in the RTL land doesn't
necessarily influence wide-int which is purely separate.  So if you
argue that having a mode in RTL constants would be soo nice and
thus that is why you want a precision in wide-int then I don't follow
that argument.  If you want a mode in RTL constants then get a mode
in RTL constants!

This would make it immediately obvious where to get the precision
for wide-ints - something you do not address at all (and as you don't
I sort of cannot believe the 'it would be so nice to have a mode on RTL
constants').

That said, if modes on RTL constants were so useful then why not
have them on CONST_WIDE_INT at least?  Please.  Only sticking
them to wide-int in form of a precision is completely backward to me
(and I still think the core wide-int shouldn't have a precision, and if
you really want a wide-int-with-precision simply derive from wide-int).

>> Ok, so please then make all CONST_INTs and CONST_DOUBLEs have
>> a mode!
>
> I'm saying that CONST_INT and CONST_DOUBLE already have a mode, but that
> mode is not stored in the rtx.  So if you're saying "make all CONST_INTs
> and CONST_DOUBLEs _store_ a mode", then yeah, I'd like to :-)  But I see
> Kenny's patch as a prerequisite for that, because it consolidates the
> CONST_INT and CONST_DOUBLE code so that the choice of rtx code is
> less special.  Lots more work is needed after that.

If there were a separate patch consolidating the paths I'd be all for
doing that.
I don't see a reason that this cannot be done even with the current
code using double-ints.

> Although TBH, the huge pushback that Kenny has got from this patch
> puts me off ever trying that change.

Well.  The patch does so much together and is so large that makes
it basically unreviewable (or very hard to review at least).

> But storing the mode in the rtx is orthogonal to what Kenny is doing.
> The mode of each rtx constant is already available in the places
> that Kenny is changing, because we already do the work to keep track
> of the mode separately.  Being able to get the mode directly from the
> rtx would be simpler and IMO better, but the semantics are the same
> either way.

Well, you showed examples where it is impossible to get at the mode.

> Kenny's patch is not designed to "fix" the CONST_INT representation
> (although the patch does make it easier to "fix" the representation
> in future).  Kenny's patch is about representing and handling constants
> that we can't at the moment.

No, it is about much more.

> The argument isn't whether CONST_WIDE_INT repeats "mistakes" made for
> CONST_INT and CONST_DOUBLE; I hope we agree that CONST_WIDE_INT should
> behave like the other two, whatever that is.  The argument is about
> whether we copy the "mistake" into the wide_int class.

I don't see how CONST_WIDE_INT is in any way related to wide_int other
than that you use wide_int to operate on the constants encoded in
CONST_WIDE_INT.  As you have a mode available at the point you
create a wide_int from a CONST_WIDE_INT you can very easily just
use that modes precision to specify the precision of an operation
(or zero/sign-extend the result).  That's what happens hidden in the
wide-int implementation currently, but in the awkward way that allows
precision mismatches and leads to odd things like having a wide-int
1 constant with a precision.

> Storing a precision in wide_int in no way requires CONST_WIDE_INT
> to store a mode.  They are separate choices.

Yes.  And I obviously would have chosed to store a mode in CONST_WIDE_INT
and no precision in wide_int.  And I cannot see a good reason to
do it the way you did it ;)

>> The solution is not to have a CONST_WIDE_INT (again with VOIDmode
>> and no precision in the RTX object(!)) and only have wide_int have a
>> precision.
>
> Why is having a VOIDmode CONST_WIDE_INT any worse than having
> a VOIDmode CONST_INT or CONST_DOUBLE?  In all three cases the mode
> is being obtained/inferred from the same external source.

Well, we're arguing in circles - the argument that VOIDmode CONST_INT/DOUBLE
are bad is yours.  And if that's not bad I can't see why it is bad for wide-int
to not have a mode (or precision).

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 12:46                                                                                                   ` Kenneth Zadeck
@ 2013-05-03 13:02                                                                                                     ` Richard Biener
  2013-05-03 14:34                                                                                                       ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-05-03 13:02 UTC (permalink / raw)
  To: Kenneth Zadeck
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Fri, May 3, 2013 at 2:45 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
> On 05/03/2013 07:19 AM, Richard Biener wrote:
>>
>> On Wed, Apr 24, 2013 at 5:29 PM, Richard Sandiford
>> <rdsandiford@googlemail.com> wrote:
>>>
>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>
>>>> On Wed, Apr 24, 2013 at 4:35 PM, Kenneth Zadeck
>>>> <zadeck@naturalbridge.com> wrote:
>>>>>
>>>>> On 04/24/2013 09:36 AM, Richard Biener wrote:
>>>>>>
>>>>>> On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford
>>>>>> <rdsandiford@googlemail.com> wrote:
>>>>>>>
>>>>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>>>>
>>>>>>>> Can we in such cases please to a preparatory patch and change the
>>>>>>>> CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
>>>>>>>> mode precision first?
>>>>>>>
>>>>>>> I'm not sure what you mean here.  CONST_INT HWIs are already
>>>>>>> sign-extended
>>>>>>> from mode precision to HWI precision.  The 8-bit value 0xb10000000
>>>>>>> must
>>>>>>> be
>>>>>>> represented as (const_int -128); nothing else is allowed.  E.g.
>>>>>>> (const_int 128)
>>>>>>> is not a valid QImode value on BITS_PER_UNIT==8 targets.
>>>>>>
>>>>>> Yes, that's what I understand.  But consider you get a CONST_INT that
>>>>>> is
>>>>>> _not_ a valid QImode value.  Current code simply trusts that it is,
>>>>>> given
>>>>>> the context from ...
>>>>>
>>>>> And the fact that it we have to trust but cannot verify is a severe
>>>>> problem
>>>>> at the rtl level that is not going to go away.    what i have been
>>>>> strongly
>>>>> objecting to is your idea that just because we cannot verify it, we can
>>>>> thus
>>>>> go change it in some completely different way (i.e. the infinite
>>>>> precision
>>>>> nonsense that you keep hitting us with) and it will all be ok.
>>>>
>>>> Appearantly it is all ok because that's exactly what we have today (and
>>>> had for the last 25 years).  CONST_INT encodes infinite precision signed
>>>> values (with the complication that a QImode 0x80 isn't valid, thus all
>>>> modes are signed as well it seems).
>>>
>>> I think this is the fundamental disagreement.  Your last step doesn't
>>> follow.  RTL integer modes are neither signed nor unsigned.  They are
>>> just a collection of N bits.  The fact that CONST_INTs represent
>>> smaller-than-HWI integers in sign-extended form is purely a represential
>>> detail.  There are no semantics attached to it.  We could just as easily
>>> have decided to extend with zeros or ones instead of sign bits.
>>>
>>> Although the decision was made before my time, I'm pretty sure the
>>> point of having a canonical representation (which happened to be sign
>>> extension) was to make sure that any given rtl constant has only a
>>> single representation.  It would be too confusing if a QImode 0x80 could
>>> be represented as either (const_int 128) or (const_int -128) (would
>>> (const_int 384) then also be OK?).
>>
>> No, not as value for a QImode as it doesn't fit there.
>>
>>> And that's the problem with using an infinite-precision wide_int.
>>> If you directly convert a CONST_INT representation of 0x80 into a
>>> wide_int, you will always get infinite-precision -128, thanks to the
>>> CONST_INT canonicalisation rule.  But if you arrive at 0x80 though
>>> arithmetic, you might get infinite-precision 128 instead.  These two
>>> values would not compare equal.
>>
>> That's true.  Note that I am not objecting to the canonicalization choice
>> for the RTL object.  On trees we do have -128 and 128 QImode integers
>> as tree constants have a sign.
>>
>> So we clearly cannot have wide_int make that choice, but those that
>> create either a tree object or a RTL object have to do additional
>> canonicalization (or truncation to not allow a QImode 384).
>>
>> Yes, I'm again arguing that making choices for wide_int shouldn't be
>> done because it seems right for RTL or right for how a CPU operates.
>> But we are mixing two things in this series of patches - introduction
>> of an additional RTX object kind CONST_WIDE_INT together with
>> deciding on its encoding of constant values, and introduction of
>> a wide_int class as a vehicle to do arithmetic on the host for larger
>> than HOST_WIDE_INT values.
>>
>> The latter could be separated by dropping CONST_DOUBLE in favor
>> of CONST_WIDE_INT everywhere and simply providing a
>> CONST_WIDE_INT <-> double-int interface (both ways, so you'd
>> actually never generate a CONST_WIDE_INT that doesn't fit a double-int).
>
> Given the tree world, i am surprised that you would push in this direction.
> While i do see some benefit for having two reps for ints at the rtl level, I
> understand the argument that is one too many.
>
> The target_supports_wide_int is a transitional trick.   The idea is to move
> the ports away from using CONST_DOUBLE at all for ints. Not only is this a
> step towards putting a mode in an rtl int const, but it also would allow the
> floating point world to move beyond the limits that sharing the rep with
> integers imposes.
>
> One of the big goals of this cleanup is to get rid of the three path
> implementation for integer math:
> constant fits in HWI - good implementation.
> constant fits in 2 HWIs - spotty implementation.
> constant needs more than 2 HWIs - ice or get wrong answer.
>
> Doing a trick like this just makes it harder to unify everything into the
> good implementation category.
>
>
>>
>>>> CONST_DOUBLE encodes infinite precision signed values as well.  Just
>>>> the "infinite" is limited by the size of the encoding, one and two
>>>> HOST_WIDE_INTs.
>>>
>>> It encodes an N-bit integer.  It's just that (assuming non-power-of-2
>>> modes) several N-bit integers (with varying N) can be encoded using the
>>> same CONST_DOUBLE representation.  That might be what you meant, sorry,
>>> and so might seem pedantic, but I wasn't sure.
>>
>> Yes, that's what I meant.  Being able to share the same RTX object for
>> constants with the same representation but a different mode is nice
>> and looks appealing (of course works only when the actual mode stored
>> in the RTX object is then sth like VOIDmode ...).  That we have gazillions
>> of NULL pointer constants on trees (for each pointer type) isn't.
>>
>> Richard.
>
> 4 gb of memory is less than $30US.   We need to move on.   The pain that no
> mode causes is significant.

I think you should stop arguing that way as you two confuse me with
two opposite views here.  Richard says having no mode on constants
is very much fine (but it would be convenient to have one).  You say
you absolutely want a mode but you do not add one to CONST_WIDE_INT.

?

Btw, I arrived at reviewing the patches for the introduction of wide_int
(separate from the RTL side) as vehicle of eventually replacing double-int.
It has good design goals but you get yourself too much influenced by
what you think are RTL/tree weaknesses or strengths.

Now I feel being dragged into a RTL IL discussion ... which isn't my
primary area of knowledge (nor interest).  Unfortunately nobody else
but the patch authors and me seem to be keen enough to get involved here ...

Just to ask again - is there a branch to look at the patches and produce
patches against?

Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 12:48                                                                                                                 ` Richard Sandiford
@ 2013-05-03 13:06                                                                                                                   ` Richard Biener
  2013-05-03 13:23                                                                                                                     ` Richard Sandiford
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Biener @ 2013-05-03 13:06 UTC (permalink / raw)
  To: Kenneth Zadeck, Richard Biener, Mike Stump, gcc-patches,
	Lawrence Crowl, Ian Lance Taylor, rdsandiford

On Fri, May 3, 2013 at 2:48 PM, Richard Sandiford
<rdsandiford@googlemail.com> wrote:
> Kenneth Zadeck <zadeck@naturalbridge.com> writes:
>> There are several problems with just dropping a mode into the already
>> existing mode field of an rtx constant.
>> 1) There may be places where the a back end is testing equality to see
>> if constants of different modes are in fact the same value.
>> 2) Most of the places what build int constants use GEN_INT which does
>> not take a mode, even though about 95% of those places have a mode right
>> there and the rest just take a little work.    There are constructor
>> that do take a mode, but in the end they just throw the mode on the floor.
>> 3) The canonical test to see if a CONST_DOUBLE contains an int or float
>> is to test if the mode is VOIDmode.
>>
>> Any port that is converted to have TARGET_SUPPORTS_WIDE_INT has no more
>> of problem (3).   I admit that rooting out (1) is likely to be the worst
>> of the problems.   But we were careful to at least make this work move
>> us in the correct direction.
>
> I agree with that, and FWIW, there are others.  Two off the top of my head:
>
> 4) Many places use const0_rtx instead of CONST0_RTX (mode) (correctly,
>    according to current representation)

As it's easy from the context to get at a mode just drop const0_rtx
and fix the fallout? (and complicate the CONST0_RTX macro to
dispatch to const_int_rtx for integer modes)

> 5) All const_ints in the .md files would need to be given a mode
>    (except for those places where const_int actually represents
>    a C++ constant, such as in attributes).
>
> I realise your list wasn't supposed to be exhaustive, and neither's mine :-)

Now, do you think it is a good idea to assign integer constants a mode
or not?

Richard.

> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 13:06                                                                                                                   ` Richard Biener
@ 2013-05-03 13:23                                                                                                                     ` Richard Sandiford
  2013-05-03 15:32                                                                                                                       ` Kenneth Zadeck
  0 siblings, 1 reply; 217+ messages in thread
From: Richard Sandiford @ 2013-05-03 13:23 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Richard Biener <richard.guenther@gmail.com> writes:
>> 5) All const_ints in the .md files would need to be given a mode
>>    (except for those places where const_int actually represents
>>    a C++ constant, such as in attributes).
>>
>> I realise your list wasn't supposed to be exhaustive, and neither's mine :-)
>
> Now, do you think it is a good idea to assign integer constants a mode
> or not?

I think the answer was obvious: good idea.  But it's an aspiration.
The huge amount of work involved means that it's out of scope unless
someone has several spare months on their hands.

The equivalent choice for wide_ints is not an aspiration.  The choice
is in ours hands.  So why force the class to use the old, problematic
model that rtl followed when (a) there are no compatiblity reasons
to do so and (b) Kenny has already written an implementation that
does it the better way?

The main reason we share the same CONST_INT and CONST_DOUBLE representation
for distinct constants is to save memory.  Even that's not an advantage
for wide_int, since wide_ints are supposed to be short-lived stack objects.

Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 12:53                                                                                                             ` Richard Biener
@ 2013-05-03 13:50                                                                                                               ` Richard Sandiford
  2013-05-03 14:27                                                                                                               ` Kenneth Zadeck
  1 sibling, 0 replies; 217+ messages in thread
From: Richard Sandiford @ 2013-05-03 13:50 UTC (permalink / raw)
  To: Richard Biener
  Cc: Kenneth Zadeck, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor

Richard Biener <richard.guenther@gmail.com> writes:
>> But storing the mode in the rtx is orthogonal to what Kenny is doing.
>> The mode of each rtx constant is already available in the places
>> that Kenny is changing, because we already do the work to keep track
>> of the mode separately.  Being able to get the mode directly from the
>> rtx would be simpler and IMO better, but the semantics are the same
>> either way.
>
> Well, you showed examples where it is impossible to get at the mode.

No, I showed examples where the mode is not inherent in the rtl.
That's a very different thing.  I wrote that in respnose to:

Richard Biener <richard.guenther@gmail.com> writes:
> Ok, so what wide-int provides is integer values encoded in 'len' HWI
> words that fit in 'precision' or more bits (and often in less).  wide-int
> also provides N-bit arithmetic operations.  IMHO both are tied
> too closely together.  A give constant doesn't really have a precision.
> Associating one with it to give a precision to an arithmetic operation
> looks wrong to me and are a source of mismatches.
>
> What RTL currently has looks better to me - operations have
> explicitely specified precisions.

That is, you seemed to be arguing that constants don't need a precision
because, whenever you do anything with them, the operator tells you
what precision the constant has.  And you seemed to be citing rtl
as proof of that.

What I was trying to show is that the operator _doesn't_ tell you the
precision in all cases.  Instead, the operands always have their own
precision, and there are rules about which combinations of operand and
operator precision are allowed.  For most binary operations the three
precisions have to be the same.  For things like popcount there's no
real restriction: the precision of the thing being counted and the
precision of the result can be arbitrarily different.  For things like
zero_extend the operator precision must be greater than the operand
precision.  Etc.

The onus is then on the rtl code to keep track of both the operator
and operand precisions where necessary.  _And the current rtl code
already tries to do that_[*].  The cselib example I gave is one place
where we take special measures.  See also things like:

  /* Now recursively process each operand of this operation.  We need to
     handle ZERO_EXTEND specially so that we don't lose track of the
     inner mode.  */
  if (GET_CODE (x) == ZERO_EXTEND)
    {
      new_rtx = make_compound_operation (XEXP (x, 0), next_code);
      tem = simplify_const_unary_operation (ZERO_EXTEND, GET_MODE (x),
					    new_rtx, GET_MODE (XEXP (x, 0)));
      if (tem)
	return tem;
      SUBST (XEXP (x, 0), new_rtx);
      return x;
    }

in combine.c, which is there specifically because this code still knows
the mode of both the operand and operator.

So all this was trying to dispel the idea that:

(a) rtl constants don't have a mode
(b) the mode of an operator tells you the mode of the operands

Neither is really true.  Instead, every rtl constant has a precision/mode.
Every tree constant likewise has a precision.  The main purpose of wide_int
is to handle compile-time arithmetic on rtl constants and tree constants,
and if both of those have a precision, it seems strange that wide_int
shouldn't.  It just pushes the onus of tracking the precision onto the
callers, like the current rtl representation does.  And the examples
I've been giving were supposed to show what a hassle that can be.

  [*] Highlighted because that's why storing a mode in a CONST_INT or
      CONST_DOUBLE isn't a prerequisite for Kenny's patch.  The mode
      is already to hand where it needs to be.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 12:40                                                                                                                 ` Richard Biener
@ 2013-05-03 14:09                                                                                                                   ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-05-03 14:09 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On 05/03/2013 08:40 AM, Richard Biener wrote:
> On Fri, May 3, 2013 at 2:31 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> On 05/03/2013 08:12 AM, Richard Biener wrote:
>>> On Fri, May 3, 2013 at 1:49 PM, Kenneth Zadeck <zadeck@naturalbridge.com>
>>> wrote:
>>>> On 05/03/2013 07:34 AM, Richard Biener wrote:
>>>>> On Thu, Apr 25, 2013 at 1:18 AM, Kenneth Zadeck
>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>> On 04/24/2013 11:13 AM, Richard Biener wrote:
>>>>>>> On Wed, Apr 24, 2013 at 5:00 PM, Richard Sandiford
>>>>>>> <rdsandiford@googlemail.com>  wrote:
>>>>>>>> Richard Biener<richard.guenther@gmail.com>  writes:
>>>>>>>>> On Wed, Apr 24, 2013 at 4:29 PM, Richard Sandiford
>>>>>>>>> <rdsandiford@googlemail.com>  wrote:
>>>>>>>>>> In other words, one of the reasons wide_int can't be exactly 1:1
>>>>>>>>>> in practice is because it is clearing out these mistakes (GEN_INT
>>>>>>>>>> rather than gen_int_mode) and missing features (non-power-of-2
>>>>>>>>>> widths).
>>>>>>>>> Note that the argument should be about CONST_WIDE_INT here,
>>>>>>>>> not wide-int.  Indeed CONST_WIDE_INT has the desired feature
>>>>>>>>> and can be properly truncated/extended according to mode at the time
>>>>>>>>> we
>>>>>>>>> build it
>>>>>>>>> via immed_wide_int_cst (w, mode).  I don't see the requirement that
>>>>>>>>> wide-int itself is automagically providing that truncation/extension
>>>>>>>>> (though it is a possibility, one that does not match existing
>>>>>>>>> behavior
>>>>>>>>> of
>>>>>>>>> HWI for CONST_INT or double-int for CONST_DOUBLE).
>>>>>>>> I agree it doesn't match the existing behaviour of HWI for CONST_INT
>>>>>>>> or
>>>>>>>> double-int for CONST_DOUBLE, but I think that's very much a good
>>>>>>>> thing.
>>>>>>>> The model for HWIs at the moment is that you have to truncate results
>>>>>>>> to the canonical form after every operation where it matters.  As you
>>>>>>>> proved in your earlier message about the plus_constant bug, that's
>>>>>>>> easily
>>>>>>>> forgotten.  I don't think the rtl code is doing all CONST_INT
>>>>>>>> arithmetic
>>>>>>>> on full HWIs because it wants to: it's doing it because that's the
>>>>>>>> way
>>>>>>>> C/C++ arithmetic on primitive types works.  In other words, the
>>>>>>>> current
>>>>>>>> CONST_INT code is trying to emulate N-bit arithmetic (for gcc runtime
>>>>>>>> N)
>>>>>>>> using a single primitive integer type.  wide_int gives us N-bit
>>>>>>>> arithmetic
>>>>>>>> directly; no emulation is needed.
>>>>>>> Ok, so what wide-int provides is integer values encoded in 'len' HWI
>>>>>>> words that fit in 'precision' or more bits (and often in less).
>>>>>>> wide-int
>>>>>>> also provides N-bit arithmetic operations.  IMHO both are tied
>>>>>>> too closely together.  A give constant doesn't really have a
>>>>>>> precision.
>>>>>>> Associating one with it to give a precision to an arithmetic operation
>>>>>>> looks wrong to me and are a source of mismatches.
>>>>>>>
>>>>>>> What RTL currently has looks better to me - operations have
>>>>>>> explicitely specified precisions.
>>>>>> I have tried very hard to make wide-int work very efficiently with both
>>>>>> tree
>>>>>> and rtl without biasing the rep towards either representation.  Both
>>>>>> rtl
>>>>>> and
>>>>>> trees constants have a precision.   In tree, constants are done better
>>>>>> than
>>>>>> in rtl because the tree really does have a field that is filled in that
>>>>>> points to a type. However, that does not mean that rtl constants do not
>>>>>> have
>>>>>> a precision: currently you have to look around at the context to find
>>>>>> the
>>>>>> mode of a constant that is in your hand, but it is in fact always
>>>>>> there.
>>>>>> At the rtl level, you can see the entire patch - we always find an
>>>>>> appropriate mode.
>>>>> Appearantly you cannot.  See Richard S. examples.
>>>>>
>>>>> As of "better", the tree has the issue that we have so many unshared
>>>>> constants because they only differ in type but not in their
>>>>> representation.
>>>>> That's the nice part of RTL constants all having VOIDmode ...
>>>>>
>>>>> Richard.
>>>> I said we could always find a mode, i did not say that in order to find
>>>> the
>>>> mode we did not have to stand on our head, juggle chainsaws and say
>>>> "mother
>>>> may i".   The decision to leave the mode as void in rtl integer constants
>>>> was made to save space, but comes with an otherwise very high cost and in
>>>> today's world of cheap memory seems fairly dated.   It is a decision that
>>>> i
>>>> and others would love to change and the truth is wide int is one step in
>>>> that direction (in that it gets rid of the pun of using double-int for
>>>> both
>>>> integers and floats where the discriminator is voidmode for ints.) But
>>>> for
>>>> now we have to live with that poor decision.
>>> As far as I have read your wide-int patches the CONST_WIDE_INT RTX
>>> object does not include a mode.  So I don't see it as a step forward in
>>> any way (other than that it makes it explicit that you _do_ need a mode
>>> to do any operation on a constant).
>>>
>>> Richard.
>> There are several problems with just dropping a mode into the already
>> existing mode field of an rtx constant.
>> 1) There may be places where the a back end is testing equality to see if
>> constants of different modes are in fact the same value.
> That supposedly only happens in places where both RTX objects are
> know to be constants.  Which makes me guess that it's in 99% of the
> cases a comparison against one of the static RTX objects like
> const0_rtx - thus easily greppable for (and easily converted similar
> to the tree case where we have predicates for such tests like integer_zerop ()).
> The remaining cases would be missed optimizations at most.
>
>> 2) Most of the places what build int constants use GEN_INT which does not
>> take a mode, even though about 95% of those places have a mode right there
>> and the rest just take a little work.    There are constructor that do take
>> a mode, but in the end they just throw the mode on the floor.
> The fix is easy - make GEN_INT take a mandatory mode argument.
> (and fix the fallout ...)
>
>> 3) The canonical test to see if a CONST_DOUBLE contains an int or float is
>> to test if the mode is VOIDmode.
> I think you addressed this already by introducing CONST_DOUBLE_AS_INT_P ().
>
>> Any port that is converted to have TARGET_SUPPORTS_WIDE_INT has no more of
>> problem (3).   I admit that rooting out (1) is likely to be the worst of the
>> problems.   But we were careful to at least make this work move us in the
>> correct direction.
> Well, you were careful to not walk in the wrong direction.  But I cannot see
> were you get closer to fix any of 1-3 (apart from considering the new predicates
> being that, or not overloading CONST_DOUBLE with floats and ints).
>
> Richard.
I understand the process, but it is unreasonable to expect me to do that 
for this.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 12:53                                                                                                             ` Richard Biener
  2013-05-03 13:50                                                                                                               ` Richard Sandiford
@ 2013-05-03 14:27                                                                                                               ` Kenneth Zadeck
  1 sibling, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-05-03 14:27 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On 05/03/2013 08:53 AM, Richard Biener wrote:
> On Fri, May 3, 2013 at 2:37 PM, Richard Sandiford
> <rdsandiford@googlemail.com> wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>>> See e.g. the hoops that cselib has to jump through:
>>>>
>>>> /* We need to pass down the mode of constants through the hash table
>>>>     functions.  For that purpose, wrap them in a CONST of the appropriate
>>>>     mode.  */
>>>> static rtx
>>>> wrap_constant (enum machine_mode mode, rtx x)
>>>> {
>>>>    if ((!CONST_SCALAR_INT_P (x)) && GET_CODE (x) != CONST_FIXED)
>>>>      return x;
>>>>    gcc_assert (mode != VOIDmode);
>>>>    return gen_rtx_CONST (mode, x);
>>>> }
>>>>
>>>> That is, cselib locally converts (const_int X) into (const:M (const_int X)),
>>>> purely so that it doesn't lose track of the CONST_INT's mode.
>>>> (const:M (const_int ...)) is invalid rtl elsewhere, but a necessary
>>>> hack here all the same.
>>> Indeed ugly.  But I wonder why cselib needs to store constants in
>>> hashtables at all ... they should be VALUEs themselves.  So the fix
>>> for the above might not necessarily be to assign the CONST_INT
>>> a mode (not that CONST_WIDE_INT would fix the above).
>> I don't understand.  Do you mean that cselib values ought to have
>> a field to say whether the value is constant or not, and if so, what
>> constant that is?  That feels like just the same kind of hack as the above.
>> The current idea of chaining all known equivalent rtxes in a list seems
>> more natural than having a list of all known equivalent rtxes except
>> CONST_INT and CONST_DOUBLE, which have to be stored separately instead.
>> (Again, we have runtime constants like SYMBOL_REF, which store modes,
>> and which would presumably still be in the normal rtx list.)
>>
>> CONST_WIDE_INT was never supposed to solve this problem.  I'm just giving
>> it as an example to back up the argument that rtx constants do in fact
>> have modes (although those modes are not stored in the rtx).  The code
>> above is there to make sure that equivalence stays transitive.
>> Without it we could have bogus equivalences like:
>>
>>    (A) (reg:DI X) == (const_int Y) == (reg:SI Z)
>>
>> even though it cannot be the case that:
>>
>>    (B) (reg:DI X) == (reg:SI Z)
>>
>> My point is that, semantically, (A) did not come from X and Z being
>> equivalent to the "same" constant.  X was equivalent to (const_int:DI Y)
>> and Z was equivalent to (const_int:SI Y).  (A) only came about because
>> we happen to use the same rtx object to represent those two semantically-
>> distinct constants.
>>
>> The idea isn't to make CONST_WIDE_INT get rid of the code above.
>> The idea is to make sure that wide_int has a precision and so doesn't
>> require code like the above to be written when dealing with wide_ints.
>>
>> In other words, I got the impression your argument was "the fact
>> that CONST_INT and CONST_DOUBLE don't store a mode shows that
>> wide_int shouldn't store a precision".  But the fact that CONST_INT
>> and CONST_DOUBLE don't store a mode doesn't mean they don't _have_
>> a mode.  You just have to keep track of that mode separately.
>> And the same would apply to wide_int if we did the same thing there.
>>
>> What I was trying to argue was that storing the mode/precision
>> separately is not always easy.  It's also much less robust,
>> because getting the wrong mode or precision will only show up
>> for certain values.  If the precision is stored in the wide_int,
>> mismatches can be asserted for based on precision alone, regardless
>> of the value.
> I was just arguing that pointing out facts in the RTL land doesn't
> necessarily influence wide-int which is purely separate.  So if you
> argue that having a mode in RTL constants would be soo nice and
> thus that is why you want a precision in wide-int then I don't follow
> that argument.  If you want a mode in RTL constants then get a mode
> in RTL constants!
>
> This would make it immediately obvious where to get the precision
> for wide-ints - something you do not address at all (and as you don't
> I sort of cannot believe the 'it would be so nice to have a mode on RTL
> constants').
>
> That said, if modes on RTL constants were so useful then why not
> have them on CONST_WIDE_INT at least?  Please.  Only sticking
> them to wide-int in form of a precision is completely backward to me
> (and I still think the core wide-int shouldn't have a precision, and if
> you really want a wide-int-with-precision simply derive from wide-int).
>
>>> Ok, so please then make all CONST_INTs and CONST_DOUBLEs have
>>> a mode!
>> I'm saying that CONST_INT and CONST_DOUBLE already have a mode, but that
>> mode is not stored in the rtx.  So if you're saying "make all CONST_INTs
>> and CONST_DOUBLEs _store_ a mode", then yeah, I'd like to :-)  But I see
>> Kenny's patch as a prerequisite for that, because it consolidates the
>> CONST_INT and CONST_DOUBLE code so that the choice of rtx code is
>> less special.  Lots more work is needed after that.
> If there were a separate patch consolidating the paths I'd be all for
> doing that.
> I don't see a reason that this cannot be done even with the current
> code using double-ints.
>
>> Although TBH, the huge pushback that Kenny has got from this patch
>> puts me off ever trying that change.
> Well.  The patch does so much together and is so large that makes
> it basically unreviewable (or very hard to review at least).
>
>> But storing the mode in the rtx is orthogonal to what Kenny is doing.
>> The mode of each rtx constant is already available in the places
>> that Kenny is changing, because we already do the work to keep track
>> of the mode separately.  Being able to get the mode directly from the
>> rtx would be simpler and IMO better, but the semantics are the same
>> either way.
> Well, you showed examples where it is impossible to get at the mode.
>
>> Kenny's patch is not designed to "fix" the CONST_INT representation
>> (although the patch does make it easier to "fix" the representation
>> in future).  Kenny's patch is about representing and handling constants
>> that we can't at the moment.
> No, it is about much more.
>
>> The argument isn't whether CONST_WIDE_INT repeats "mistakes" made for
>> CONST_INT and CONST_DOUBLE; I hope we agree that CONST_WIDE_INT should
>> behave like the other two, whatever that is.  The argument is about
>> whether we copy the "mistake" into the wide_int class.
> I don't see how CONST_WIDE_INT is in any way related to wide_int other
> than that you use wide_int to operate on the constants encoded in
> CONST_WIDE_INT.  As you have a mode available at the point you
> create a wide_int from a CONST_WIDE_INT you can very easily just
> use that modes precision to specify the precision of an operation
> (or zero/sign-extend the result).  That's what happens hidden in the
> wide-int implementation currently, but in the awkward way that allows
> precision mismatches and leads to odd things like having a wide-int
> 1 constant with a precision.
i do not have a problem with putting the mode into CONST_WIDE_INT. It is 
that it just would not help anything now.    As you may have seen, the 
idiom that i use is to have a single wide-int constructor that does the 
correct thing no matter which of the three forms is passed in.   So the 
fact that only one of the three forms has the mode is of little use.

Again, if you want infinite precision then use mpc.   Given some of your 
comments on this patch, i do not think that you actually appreciate how 
much mileage we get out of having the precision. Doing fixed precision 
math allows me to do the precision fits in a HWI case inline with no 
function calls and no checking for carrys and such.

If i did infinite precision then i am stuck with a loop around every 
operation to take it as far as it needs to go.   Then, for performance 
reasons, that is going to force me live in the world where we have one 
implementation for things that fit in hwi and things that do not, and 
then people will, as they currently do, not do the work for the longer 
types.

>> Storing a precision in wide_int in no way requires CONST_WIDE_INT
>> to store a mode.  They are separate choices.
> Yes.  And I obviously would have chosed to store a mode in CONST_WIDE_INT
> and no precision in wide_int.  And I cannot see a good reason to
> do it the way you did it ;)
because if i say a* b + c, i need the precision in the middle, otherwise 
i am stuck doing infinite precision arithmetic which is not what i want 
and will perform too slowly to be generally useful.   I do not 
understand why you do not get this!!!!    I did not do infinite 
precision because i was lazy or because i was forced to by some 
weirdness in rtl.   I did it because it is the right way to do the math 
in the compiler after the front ends do the language specified "constant 
math" and because infinite precision is too expensive.    Double int is 
not infinite precision, it is fixed precision at 128 bits and if the 
number does not fit in that, the compiler ices.

>
>>> The solution is not to have a CONST_WIDE_INT (again with VOIDmode
>>> and no precision in the RTX object(!)) and only have wide_int have a
>>> precision.
>> Why is having a VOIDmode CONST_WIDE_INT any worse than having
>> a VOIDmode CONST_INT or CONST_DOUBLE?  In all three cases the mode
>> is being obtained/inferred from the same external source.
> Well, we're arguing in circles - the argument that VOIDmode CONST_INT/DOUBLE
> are bad is yours.  And if that's not bad I can't see why it is bad for wide-int
> to not have a mode (or precision).
I have said enough on this.


>
> Richard.
>
>> Richard

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 13:02                                                                                                     ` Richard Biener
@ 2013-05-03 14:34                                                                                                       ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-05-03 14:34 UTC (permalink / raw)
  To: Richard Biener
  Cc: Mike Stump, gcc-patches, Lawrence Crowl, Ian Lance Taylor, rdsandiford

On 05/03/2013 09:02 AM, Richard Biener wrote:
> On Fri, May 3, 2013 at 2:45 PM, Kenneth Zadeck <zadeck@naturalbridge.com> wrote:
>> On 05/03/2013 07:19 AM, Richard Biener wrote:
>>> On Wed, Apr 24, 2013 at 5:29 PM, Richard Sandiford
>>> <rdsandiford@googlemail.com> wrote:
>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>> On Wed, Apr 24, 2013 at 4:35 PM, Kenneth Zadeck
>>>>> <zadeck@naturalbridge.com> wrote:
>>>>>> On 04/24/2013 09:36 AM, Richard Biener wrote:
>>>>>>> On Wed, Apr 24, 2013 at 2:44 PM, Richard Sandiford
>>>>>>> <rdsandiford@googlemail.com> wrote:
>>>>>>>> Richard Biener <richard.guenther@gmail.com> writes:
>>>>>>>>> Can we in such cases please to a preparatory patch and change the
>>>>>>>>> CONST_INT/CONST_DOUBLE paths to do an explicit [sz]ext to
>>>>>>>>> mode precision first?
>>>>>>>> I'm not sure what you mean here.  CONST_INT HWIs are already
>>>>>>>> sign-extended
>>>>>>>> from mode precision to HWI precision.  The 8-bit value 0xb10000000
>>>>>>>> must
>>>>>>>> be
>>>>>>>> represented as (const_int -128); nothing else is allowed.  E.g.
>>>>>>>> (const_int 128)
>>>>>>>> is not a valid QImode value on BITS_PER_UNIT==8 targets.
>>>>>>> Yes, that's what I understand.  But consider you get a CONST_INT that
>>>>>>> is
>>>>>>> _not_ a valid QImode value.  Current code simply trusts that it is,
>>>>>>> given
>>>>>>> the context from ...
>>>>>> And the fact that it we have to trust but cannot verify is a severe
>>>>>> problem
>>>>>> at the rtl level that is not going to go away.    what i have been
>>>>>> strongly
>>>>>> objecting to is your idea that just because we cannot verify it, we can
>>>>>> thus
>>>>>> go change it in some completely different way (i.e. the infinite
>>>>>> precision
>>>>>> nonsense that you keep hitting us with) and it will all be ok.
>>>>> Appearantly it is all ok because that's exactly what we have today (and
>>>>> had for the last 25 years).  CONST_INT encodes infinite precision signed
>>>>> values (with the complication that a QImode 0x80 isn't valid, thus all
>>>>> modes are signed as well it seems).
>>>> I think this is the fundamental disagreement.  Your last step doesn't
>>>> follow.  RTL integer modes are neither signed nor unsigned.  They are
>>>> just a collection of N bits.  The fact that CONST_INTs represent
>>>> smaller-than-HWI integers in sign-extended form is purely a represential
>>>> detail.  There are no semantics attached to it.  We could just as easily
>>>> have decided to extend with zeros or ones instead of sign bits.
>>>>
>>>> Although the decision was made before my time, I'm pretty sure the
>>>> point of having a canonical representation (which happened to be sign
>>>> extension) was to make sure that any given rtl constant has only a
>>>> single representation.  It would be too confusing if a QImode 0x80 could
>>>> be represented as either (const_int 128) or (const_int -128) (would
>>>> (const_int 384) then also be OK?).
>>> No, not as value for a QImode as it doesn't fit there.
>>>
>>>> And that's the problem with using an infinite-precision wide_int.
>>>> If you directly convert a CONST_INT representation of 0x80 into a
>>>> wide_int, you will always get infinite-precision -128, thanks to the
>>>> CONST_INT canonicalisation rule.  But if you arrive at 0x80 though
>>>> arithmetic, you might get infinite-precision 128 instead.  These two
>>>> values would not compare equal.
>>> That's true.  Note that I am not objecting to the canonicalization choice
>>> for the RTL object.  On trees we do have -128 and 128 QImode integers
>>> as tree constants have a sign.
>>>
>>> So we clearly cannot have wide_int make that choice, but those that
>>> create either a tree object or a RTL object have to do additional
>>> canonicalization (or truncation to not allow a QImode 384).
>>>
>>> Yes, I'm again arguing that making choices for wide_int shouldn't be
>>> done because it seems right for RTL or right for how a CPU operates.
>>> But we are mixing two things in this series of patches - introduction
>>> of an additional RTX object kind CONST_WIDE_INT together with
>>> deciding on its encoding of constant values, and introduction of
>>> a wide_int class as a vehicle to do arithmetic on the host for larger
>>> than HOST_WIDE_INT values.
>>>
>>> The latter could be separated by dropping CONST_DOUBLE in favor
>>> of CONST_WIDE_INT everywhere and simply providing a
>>> CONST_WIDE_INT <-> double-int interface (both ways, so you'd
>>> actually never generate a CONST_WIDE_INT that doesn't fit a double-int).
>> Given the tree world, i am surprised that you would push in this direction.
>> While i do see some benefit for having two reps for ints at the rtl level, I
>> understand the argument that is one too many.
>>
>> The target_supports_wide_int is a transitional trick.   The idea is to move
>> the ports away from using CONST_DOUBLE at all for ints. Not only is this a
>> step towards putting a mode in an rtl int const, but it also would allow the
>> floating point world to move beyond the limits that sharing the rep with
>> integers imposes.
>>
>> One of the big goals of this cleanup is to get rid of the three path
>> implementation for integer math:
>> constant fits in HWI - good implementation.
>> constant fits in 2 HWIs - spotty implementation.
>> constant needs more than 2 HWIs - ice or get wrong answer.
>>
>> Doing a trick like this just makes it harder to unify everything into the
>> good implementation category.
>>
>>
>>>>> CONST_DOUBLE encodes infinite precision signed values as well.  Just
>>>>> the "infinite" is limited by the size of the encoding, one and two
>>>>> HOST_WIDE_INTs.
>>>> It encodes an N-bit integer.  It's just that (assuming non-power-of-2
>>>> modes) several N-bit integers (with varying N) can be encoded using the
>>>> same CONST_DOUBLE representation.  That might be what you meant, sorry,
>>>> and so might seem pedantic, but I wasn't sure.
>>> Yes, that's what I meant.  Being able to share the same RTX object for
>>> constants with the same representation but a different mode is nice
>>> and looks appealing (of course works only when the actual mode stored
>>> in the RTX object is then sth like VOIDmode ...).  That we have gazillions
>>> of NULL pointer constants on trees (for each pointer type) isn't.
>>>
>>> Richard.
>> 4 gb of memory is less than $30US.   We need to move on.   The pain that no
>> mode causes is significant.
> I think you should stop arguing that way as you two confuse me with
> two opposite views here.  Richard says having no mode on constants
> is very much fine (but it would be convenient to have one).  You say
> you absolutely want a mode but you do not add one to CONST_WIDE_INT.
>
> ?
different people have different opinions.    however, the reality is 
that rtl constants have an implied mode, that is just not stored with 
constant.
>
> Btw, I arrived at reviewing the patches for the introduction of wide_int
> (separate from the RTL side) as vehicle of eventually replacing double-int.
> It has good design goals but you get yourself too much influenced by
> what you think are RTL/tree weaknesses or strengths.
Replacing double-int is my subgoal.   It is what is necessary to get to 
the place where gcc has robust support for any width integer. There are 
large parts of the compiler, at both the tree and rtl level that do not 
even use double-int: they just do the operations inline for the fits in 
HWI case and fail to try any transformation if it does not fit.    And i 
would point out that all of those places are explicitly math within a 
fixed precision.

>
> Now I feel being dragged into a RTL IL discussion ... which isn't my
> primary area of knowledge (nor interest).  Unfortunately nobody else
> but the patch authors and me seem to be keen enough to get involved here ...
I agree.
> Just to ask again - is there a branch to look at the patches and produce
> patches against?
I answered that at the bottom of the refresh of the 4th patch yesterday.

> Richard.

^ permalink raw reply	[flat|nested] 217+ messages in thread

* Re: patch to fix constant math -5th patch, rtl
  2013-05-03 13:23                                                                                                                     ` Richard Sandiford
@ 2013-05-03 15:32                                                                                                                       ` Kenneth Zadeck
  0 siblings, 0 replies; 217+ messages in thread
From: Kenneth Zadeck @ 2013-05-03 15:32 UTC (permalink / raw)
  To: Richard Biener, Mike Stump, gcc-patches, Lawrence Crowl,
	Ian Lance Taylor, rdsandiford

Richi,

I also think that it is a digression to have this discussion about 
rtl.    The root problem is really that Mike, Richard, and myself do not 
believe that infinite precision math is the proper way to do math for 
the majority of the compiler.   Most of the compiler, at both the rtl 
and tree level just does the math inline.   There are 314 places at the 
tree level where we ask if the value fits in a hwi and then we do the 
hwi inline math.   The rtl level is even more skewed towards this style 
of programming.  While you view replacing double-int as my primary goal, 
it accounts for the minority of the places in the code where wide-int 
needs to be used.

Furthermore to call what is done in double-int infinite precision is 
really pushing it.   Because it certainly is not infinite if you happen 
to have a TImode variable.

What i did when i designed wide-int was to come up with a mechanism 
where i could preserve the performance of that inline math while 
generalizing it so that it worked correctly for any width. That is why 
the precision is there.   It allows me to avoid the hard work 99% of the 
time, with an inline test of the precision and then a branch free 
calculation of the answer.   For instance there is no loop checking for 
carries and propagating them.

I also feel strongly that it is our responsibility to preserve, to the 
extent possible, the notion that optimization never changes the output 
of a program, except of course for timing.   We, in the optimization 
community, do not always so do so well here, but at the very least, we 
should always try.   Having said that, there are optimizations like VRP 
that really do need to do math larger than precision defined in the 
type.   I get this, and always have.   I understand that if you truncate 
multiplies, add or subtracts, in VRP then the resulting range is not 
simple and becomes too difficult to reasonably represent.    I have no 
intention of giving up anything in VRP.   My plan for that is to look at 
the types used in function being compiled and take the largest type, 
double the precision, and do all of the math within VRP at that expanded 
fixed precision.   We can always guarantee that we can do this in 
wide-int since the size of the buffer is computed by looking at the 
target's modes and taking the largest one those times a comfortable 
multipler.   Since you cannot have a type without a corresponding mode, 
this will always work.   This scheme preserves the behavior of VRP while 
making it work with any sized integer.
The alternative is to use a true infinite precision package for VRP but 
i think that is overkill.

Kenny

^ permalink raw reply	[flat|nested] 217+ messages in thread

end of thread, other threads:[~2013-05-03 15:32 UTC | newest]

Thread overview: 217+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-03 17:17 patch to fix Kenneth Zadeck
2012-10-03 20:47 ` Marc Glisse
2012-10-03 22:05   ` Kenneth Zadeck
2012-10-04 13:17     ` Marc Glisse
2012-10-04 15:19       ` Kenneth Zadeck
2012-10-04 16:55         ` Marc Glisse
2012-10-04 21:06     ` Marc Glisse
2012-10-04 23:02       ` Kenneth Zadeck
2012-10-05  7:05         ` Marc Glisse
2012-10-03 22:55   ` Mike Stump
2012-10-04 12:48 ` Richard Guenther
2012-10-04 13:55   ` patch to fix constant math Kenneth Zadeck
2012-10-04 16:58     ` Richard Guenther
2012-10-04 18:08       ` Kenneth Zadeck
2012-10-04 19:27         ` Richard Sandiford
2012-10-05  9:27           ` Richard Guenther
2012-10-05  9:29             ` Richard Guenther
2012-10-05  9:56             ` Richard Sandiford
2012-10-05 10:34               ` Richard Guenther
2012-10-05 11:24                 ` Richard Sandiford
2012-10-05 11:42                   ` Richard Guenther
2012-10-05 12:26                     ` Richard Sandiford
2012-10-05 12:39                       ` Richard Guenther
2012-10-05 13:11                         ` Richard Sandiford
2012-10-05 13:18                           ` Richard Sandiford
2012-10-05 13:53                             ` Richard Guenther
2012-10-05 14:15                               ` Richard Sandiford
2012-10-05 14:36                                 ` Richard Guenther
2012-10-05 14:41                                   ` Kenneth Zadeck
2012-10-05 14:53                                     ` Richard Sandiford
2012-10-05 13:49                         ` Richard Guenther
2012-10-05 16:34                           ` Kenneth Zadeck
2012-10-05 17:29                             ` Richard Sandiford
2012-10-05 17:53                               ` Kenneth Zadeck
2012-10-05 22:12                               ` patch to fix constant math - first small patch Kenneth Zadeck
2012-10-05 22:48                                 ` patch to fix constant math - second " Kenneth Zadeck
2012-10-06 15:55                                   ` patch to fix constant math - third " Kenneth Zadeck
2012-10-08  9:08                                     ` Richard Guenther
2012-10-08 11:37                                     ` Kenneth Zadeck
2012-10-08 12:11                                       ` Richard Guenther
2012-10-08 19:43                                       ` Richard Sandiford
2012-10-09 15:10                                         ` patch to fix constant math - 4th patch - the wide-int class Kenneth Zadeck
2012-10-23 14:33                                           ` Richard Biener
2012-10-23 16:25                                             ` Kenneth Zadeck
2012-10-23 18:52                                               ` Lawrence Crowl
2012-10-23 19:27                                                 ` Kenneth Zadeck
2012-10-23 20:51                                                   ` Lawrence Crowl
2012-10-23 21:34                                                     ` Kenneth Zadeck
2012-10-24 10:10                                               ` Richard Biener
2012-10-24 17:30                                                 ` Mike Stump
2012-10-25 10:55                                                   ` Richard Biener
2012-10-25 10:59                                                     ` Kenneth Zadeck
2012-10-25 12:12                                                       ` Richard Biener
2012-10-31 11:01                                                         ` Richard Sandiford
2012-10-31 12:01                                                           ` Richard Biener
2012-10-31 12:12                                                             ` Richard Sandiford
2012-10-31 12:14                                                               ` Richard Biener
2012-10-31 12:23                                                                 ` Richard Sandiford
2012-10-31 12:50                                                                   ` Richard Biener
2012-10-31 13:50                                                                     ` Richard Sandiford
2012-10-31 13:56                                                                       ` Richard Biener
2012-10-31 14:26                                                                         ` Kenneth Zadeck
2012-10-31 19:45                                                                         ` Mike Stump
2012-10-31 15:52                                                                       ` Kenneth Zadeck
2012-10-31 14:39                                                                     ` Kenneth Zadeck
2012-10-31 19:22                                                                     ` Mike Stump
2012-10-31 13:54                                                                 ` Kenneth Zadeck
2012-10-31 14:07                                                                   ` Richard Biener
2012-10-31 14:25                                                                     ` Kenneth Zadeck
2012-10-31 14:25                                                                       ` Richard Biener
2012-10-31 14:30                                                                         ` Kenneth Zadeck
2012-11-01 22:13                                                                         ` patch to fix constant math - 8th patch - tree-vrp.c Kenneth Zadeck
2012-11-01 22:28                                                                           ` Marc Glisse
2012-11-01 22:35                                                                             ` Kenneth Zadeck
2012-11-01 22:33                                                                           ` patch to fix constant math - 4th patch - wide-int.[ch] refresh Kenneth Zadeck
2012-11-01 22:36                                                                             ` Kenneth Zadeck
2012-11-30 16:46                                                                         ` patch to fix constant math - 4th patch - the wide-int class Kenneth Zadeck
2012-11-30 17:00                                                                           ` patch to fix constant math - 5th patch - the rtl level changes Kenneth Zadeck
2012-11-30 18:13                                                                             ` patch to add storage classes to wide int Kenneth Zadeck
2012-11-30 19:05                                                                               ` Kenneth Zadeck
2012-12-01  9:28                                                                               ` Richard Sandiford
2012-12-01 13:43                                                                                 ` Kenneth Zadeck
2013-02-27  1:59                                                                         ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Kenneth Zadeck
2013-03-27 14:54                                                                           ` Richard Biener
2013-04-04  8:08                                                                             ` Kenneth Zadeck
2013-04-02 15:40                                                                           ` Richard Biener
2013-04-02 19:23                                                                             ` Kenneth Zadeck
2013-04-03 10:44                                                                               ` Richard Biener
2013-04-03 13:36                                                                                 ` Kenneth Zadeck
2013-04-03 14:46                                                                                   ` Richard Biener
2013-04-03 19:18                                                                                     ` Kenneth Zadeck
2013-04-04 11:45                                                                                       ` Richard Biener
2013-04-08  5:28                                                                                         ` Comments on the suggestion to use infinite precision math for wide int Kenneth Zadeck
2013-04-08 10:32                                                                                           ` Florian Weimer
2013-04-08 13:58                                                                                             ` Kenneth Zadeck
2013-04-08 14:00                                                                                               ` Robert Dewar
2013-04-08 14:12                                                                                                 ` Kenneth Zadeck
2013-04-08 14:41                                                                                                   ` Robert Dewar
2013-04-08 15:10                                                                                                     ` Kenneth Zadeck
2013-04-08 17:18                                                                                                       ` Robert Dewar
2013-04-08 17:22                                                                                                         ` Kenneth Zadeck
2013-04-08 19:14                                                                                                           ` Robert Dewar
2013-04-08 23:48                                                                                                             ` Lawrence Crowl
2013-04-09  1:22                                                                                                               ` Robert Dewar
2013-04-09  1:56                                                                                                                 ` Kenneth Zadeck
2013-04-09  2:10                                                                                                                   ` Robert Dewar
2013-04-09  7:06                                                                                                                     ` Mike Stump
2013-04-09  8:20                                                                                                                       ` Robert Dewar
2013-04-09  8:22                                                                                                                         ` Kenneth Zadeck
2013-04-09  8:24                                                                                                                           ` Robert Dewar
2013-04-09 12:42                                                                                                                             ` Florian Weimer
2013-04-09 15:06                                                                                                                               ` Robert Dewar
2013-04-09 16:16                                                                                                                                 ` Florian Weimer
2013-04-08 13:12                                                                                           ` Richard Biener
2013-04-08 13:32                                                                                             ` Kenneth Zadeck
2013-04-08 13:44                                                                                               ` Robert Dewar
2013-04-08 14:26                                                                                                 ` Kenneth Zadeck
2013-04-08 14:35                                                                                                   ` Robert Dewar
2013-04-08 19:06                                                                                               ` Richard Biener
2013-04-08 22:34                                                                                               ` Lawrence Crowl
2013-04-09  9:47                                                                                                 ` Richard Biener
     [not found]                                                                                                   ` <CAGqM8fZ7NxiMnC6PTA8v6w_E6ZJ5HbjhJXzh-HAOJqaSx+7rnw@mail.gmail.com>
2013-04-10  9:44                                                                                                     ` Richard Biener
2013-04-10 17:43                                                                                                       ` Mike Stump
2013-04-10 17:53                                                                                                         ` Kenneth Zadeck
2013-04-08 23:46                                                                                             ` Lawrence Crowl
2013-04-22 21:39                                                                                         ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Richard Sandiford
2013-04-23  0:35                                                                                           ` Richard Biener
2013-04-23  6:47                                                                                             ` Richard Sandiford
2013-04-05 15:05                                                                             ` Kenneth Zadeck
2013-04-08 13:06                                                                               ` Richard Biener
2013-04-17  0:49                                                                                 ` Kenneth Zadeck
2013-04-17  3:41                                                                                   ` patch to fix constant math -5th patch, rtl Kenneth Zadeck
2013-04-24 13:25                                                                                     ` Richard Biener
2013-04-24 13:37                                                                                       ` Richard Sandiford
2013-04-24 14:18                                                                                         ` Richard Biener
2013-04-24 14:34                                                                                           ` Richard Sandiford
2013-04-24 14:37                                                                                             ` Richard Biener
2013-04-24 14:53                                                                                               ` Richard Sandiford
2013-04-24 15:07                                                                                                 ` Richard Biener
2013-04-24 15:13                                                                                                   ` Kenneth Zadeck
2013-04-24 15:45                                                                                                   ` Richard Sandiford
2013-04-24 16:51                                                                                                     ` Richard Biener
2013-04-24 18:24                                                                                                       ` Richard Sandiford
2013-05-03 11:28                                                                                                         ` Richard Biener
2013-05-03 12:38                                                                                                           ` Richard Sandiford
2013-05-03 12:53                                                                                                             ` Richard Biener
2013-05-03 13:50                                                                                                               ` Richard Sandiford
2013-05-03 14:27                                                                                                               ` Kenneth Zadeck
2013-04-25  8:38                                                                                                       ` Kenneth Zadeck
2013-05-03 11:34                                                                                                         ` Richard Biener
2013-05-03 11:50                                                                                                           ` Kenneth Zadeck
2013-05-03 12:12                                                                                                             ` Richard Biener
2013-05-03 12:31                                                                                                               ` Kenneth Zadeck
2013-05-03 12:40                                                                                                                 ` Richard Biener
2013-05-03 14:09                                                                                                                   ` Kenneth Zadeck
2013-05-03 12:48                                                                                                                 ` Richard Sandiford
2013-05-03 13:06                                                                                                                   ` Richard Biener
2013-05-03 13:23                                                                                                                     ` Richard Sandiford
2013-05-03 15:32                                                                                                                       ` Kenneth Zadeck
2013-04-24 14:57                                                                                           ` Kenneth Zadeck
2013-04-24 15:49                                                                                             ` Richard Biener
2013-04-24 17:11                                                                                               ` Richard Sandiford
2013-05-03 11:19                                                                                                 ` Richard Biener
2013-05-03 12:46                                                                                                   ` Kenneth Zadeck
2013-05-03 13:02                                                                                                     ` Richard Biener
2013-05-03 14:34                                                                                                       ` Kenneth Zadeck
2013-05-02 17:22                                                                                       ` Kenneth Zadeck
2013-04-17  7:34                                                                                   ` patch to fix constant math - builtins.c - the first of the tree level patches for wide-int Kenneth Zadeck
2013-05-02 17:53                                                                                     ` Kenneth Zadeck
2013-04-17 15:01                                                                                   ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Kenneth Zadeck
2013-04-19 15:35                                                                                   ` Richard Biener
2013-04-22  7:15                                                                                     ` Kenneth Zadeck
2013-04-22 15:21                                                                                       ` Richard Biener
2013-04-23  8:11                                                                                         ` Kenneth Zadeck
2013-04-22 18:53                                                                                     ` Kenneth Zadeck
2013-04-22 19:17                                                                                       ` richard, i accidently pushed send rather than save, the previous email was not finished, just ignore it Kenneth Zadeck
2013-05-02 17:21                                                                                     ` patch to fix constant math - 4th patch - the wide-int class - patch ping for the next stage 1 Kenneth Zadeck
2012-10-31 20:07                                                                     ` patch to fix constant math - 4th patch - the wide-int class Mike Stump
2012-10-23 18:10                                             ` Lawrence Crowl
2012-10-09 18:51                                         ` patch to fix constant math - patch 5 - the rest of the rtl stuff Kenneth Zadeck
2012-10-19 16:52                                           ` Richard Sandiford
2012-11-09 13:22                                         ` patch to fix constant math - third small patch Kenneth Zadeck
2012-10-08  9:07                                   ` patch to fix constant math - second " Richard Guenther
2012-11-08 18:14                                     ` Kenneth Zadeck
2012-11-26 15:31                                       ` Richard Biener
2013-02-27  0:28                                   ` patch to fix constant math - second small patch -patch ping for next stage 1 Kenneth Zadeck
2013-03-27 14:18                                     ` Richard Biener
2013-03-27 14:23                                       ` Kenneth Zadeck
2013-03-27 15:07                                         ` Richard Biener
2013-03-28 14:47                                           ` Kenneth Zadeck
2012-10-06  0:14                                 ` patch to fix constant math - first small patch Joseph S. Myers
2012-10-08 19:25                                   ` Kenneth Zadeck
2012-11-08 17:37                                   ` Kenneth Zadeck
2013-02-27  0:23                                   ` patch to fix constant math - first small patch - patch ping for the next stage 1 Kenneth Zadeck
2013-03-27 14:13                                     ` Richard Biener
2013-03-28 15:06                                       ` Kenneth Zadeck
2013-03-31 17:51                                       ` Kenneth Zadeck
2013-04-02  9:45                                         ` Richard Biener
2013-04-02 14:34                                           ` Kenneth Zadeck
2013-04-02 15:29                                             ` Richard Biener
2013-04-02 22:43                                               ` Kenneth Zadeck
2013-04-03 10:48                                                 ` Richard Biener
2013-04-03 12:21                                                   ` Kenneth Zadeck
2013-04-03 13:38                                                     ` Richard Biener
2013-04-04  3:13                                                       ` Kenneth Zadeck
2012-10-07 12:47                             ` patch to fix constant math Richard Guenther
2012-10-07 13:11                               ` Kenneth Zadeck
2012-10-07 13:19                                 ` Richard Guenther
2012-10-07 14:58                                   ` Kenneth Zadeck
2012-10-08  9:27                                     ` Richard Guenther
2012-10-08 15:01                                       ` Nathan Froyd
2012-10-08 15:11                                         ` Robert Dewar
2012-10-08 19:55                                           ` Richard Sandiford
2012-10-09  7:09                                             ` Richard Guenther
2012-10-08 16:18                                         ` Richard Guenther
2012-10-05 13:11                     ` Kenneth Zadeck
2012-10-04 15:39   ` patch to fix Kenneth Zadeck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).