poly_int: add poly-int.h
authorRichard Sandiford <richard.sandiford@linaro.org>
Thu, 14 Dec 2017 00:06:02 +0000 (00:06 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Thu, 14 Dec 2017 00:06:02 +0000 (00:06 +0000)
This patch adds a new "poly_int" class to represent polynomial integers
of the form:

  C0 + C1*X1 + C2*X2 ... + Cn*Xn

It also adds poly_int-based typedefs for offsets and sizes of various
precisions.  In these typedefs, the Ci coefficients are compile-time
constants and the Xi indeterminates are run-time invariants.  The number
of coefficients is controlled by the target and is initially 1 for all
ports.

Most routines can handle general coefficient counts, but for now a few
are specific to one or two coefficients.  Support for other coefficient
counts can be added when needed.

The patch also adds a new macro, IN_TARGET_CODE, that can be
set to indicate that a TU contains target-specific rather than
target-independent code.  When this macro is set and the number of
coefficients is 1, the poly-int.h classes define a conversion operator
to a constant.  This allows most existing target code to work without
modification.  The main exceptions are:

- values passed through ..., which need an explicit conversion to a
  constant

- ?: expression in which one arm ends up being a polynomial and the
  other remains a constant.  In these cases it would be valid to convert
  the constant to a polynomial and the polynomial to a constant, so a
  cast is needed to break the ambiguity.

The patch also adds a new target hook to return the estimated
value of a polynomial for costing purposes.

The patch also adds operator<< on wide_ints (it was already defined
for offset_int and widest_int).  I think this was originally excluded
because >> is ambiguous for wide_int, but << is useful for converting
bytes to bits, etc., so is worth defining on its own.  The patch also
adds operator% and operator/ for offset_int and widest_int, since those
types are always signed.  These changes allow the poly_int interface to
be more predictable.

I'd originally tried adding the tests as selftests, but that ended up
bloating cc1 by at least a third.  It also took a while to build them
at -O2.  The patch therefore uses plugin tests instead, where we can
force the tests to be built at -O0.  They still run in negligible time
when built that way.

2017-12-14  Richard Sandiford  <richard.sandiford@linaro.org>
    Alan Hayward  <alan.hayward@arm.com>
    David Sherwood  <david.sherwood@arm.com>

gcc/
* poly-int.h: New file.
* poly-int-types.h: Likewise.
* coretypes.h: Include them.
(POLY_INT_CONVERSION): Define.
* target.def (estimated_poly_value): New hook.
* doc/tm.texi.in (TARGET_ESTIMATED_POLY_VALUE): New hook.
* doc/tm.texi: Regenerate.
* doc/poly-int.texi: New file.
* doc/gccint.texi: Include it.
* doc/rtl.texi: Describe restrictions on subreg modes.
* Makefile.in (TEXI_GCCINT_FILES): Add poly-int.texi.
* genmodes.c (NUM_POLY_INT_COEFFS): Provide a default definition.
(emit_insn_modes_h): Emit a definition of NUM_POLY_INT_COEFFS.
* targhooks.h (default_estimated_poly_value): Declare.
* targhooks.c (default_estimated_poly_value): New function.
* target.h (estimated_poly_value): Likewise.
* wide-int.h (WI_UNARY_RESULT): Use wi::binary_traits.
(wi::unary_traits): Delete.
(wi::binary_traits::signed_shift_result_type): Define for
offset_int << HOST_WIDE_INT, etc.
(generic_wide_int::operator <<=): Define for all types and use
wi::lshift instead of <<.
(wi::hwi_with_prec): Add a default constructor.
(wi::ints_for): New class.
(operator <<): Define for all wide-int types.
(operator /): New function.
(operator %): Likewise.
* selftest.h (ASSERT_KNOWN_EQ, ASSERT_KNOWN_EQ_AT, ASSERT_MAYBE_NE)
(ASSERT_MAYBE_NE_AT): New macros.

gcc/testsuite/
* gcc.dg/plugin/poly-int-tests.h,
gcc.dg/plugin/poly-int-test-1.c,
gcc.dg/plugin/poly-int-01_plugin.c,
gcc.dg/plugin/poly-int-02_plugin.c,
gcc.dg/plugin/poly-int-03_plugin.c,
gcc.dg/plugin/poly-int-04_plugin.c,
gcc.dg/plugin/poly-int-05_plugin.c,
gcc.dg/plugin/poly-int-06_plugin.c,
gcc.dg/plugin/poly-int-07_plugin.c: New tests.
* gcc.dg/plugin/plugin.exp: Run them.

Co-Authored-By: Alan Hayward <alan.hayward@arm.com>
Co-Authored-By: David Sherwood <david.sherwood@arm.com>
From-SVN: r255617

28 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/coretypes.h
gcc/doc/gccint.texi
gcc/doc/poly-int.texi [new file with mode: 0644]
gcc/doc/rtl.texi
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/genmodes.c
gcc/poly-int-types.h [new file with mode: 0644]
gcc/poly-int.h [new file with mode: 0644]
gcc/selftest.h
gcc/target.def
gcc/target.h
gcc/targhooks.c
gcc/targhooks.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/plugin/plugin.exp
gcc/testsuite/gcc.dg/plugin/poly-int-01_plugin.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/poly-int-02_plugin.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/poly-int-03_plugin.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/poly-int-04_plugin.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/poly-int-05_plugin.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/poly-int-06_plugin.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/poly-int-07_plugin.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/poly-int-test-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/poly-int-tests.h [new file with mode: 0644]
gcc/wide-int.h

index 272bb7696f2f28654437bd29d33c756073dcb495..9d4869eadba8cf3955d4595b07d25ecc8200a15a 100644 (file)
@@ -1,3 +1,37 @@
+2017-12-14  Richard Sandiford  <richard.sandiford@linaro.org>
+           Alan Hayward  <alan.hayward@arm.com>
+           David Sherwood  <david.sherwood@arm.com>
+
+       * poly-int.h: New file.
+       * poly-int-types.h: Likewise.
+       * coretypes.h: Include them.
+       (POLY_INT_CONVERSION): Define.
+       * target.def (estimated_poly_value): New hook.
+       * doc/tm.texi.in (TARGET_ESTIMATED_POLY_VALUE): New hook.
+       * doc/tm.texi: Regenerate.
+       * doc/poly-int.texi: New file.
+       * doc/gccint.texi: Include it.
+       * doc/rtl.texi: Describe restrictions on subreg modes.
+       * Makefile.in (TEXI_GCCINT_FILES): Add poly-int.texi.
+       * genmodes.c (NUM_POLY_INT_COEFFS): Provide a default definition.
+       (emit_insn_modes_h): Emit a definition of NUM_POLY_INT_COEFFS.
+       * targhooks.h (default_estimated_poly_value): Declare.
+       * targhooks.c (default_estimated_poly_value): New function.
+       * target.h (estimated_poly_value): Likewise.
+       * wide-int.h (WI_UNARY_RESULT): Use wi::binary_traits.
+       (wi::unary_traits): Delete.
+       (wi::binary_traits::signed_shift_result_type): Define for
+       offset_int << HOST_WIDE_INT, etc.
+       (generic_wide_int::operator <<=): Define for all types and use
+       wi::lshift instead of <<.
+       (wi::hwi_with_prec): Add a default constructor.
+       (wi::ints_for): New class.
+       (operator <<): Define for all wide-int types.
+       (operator /): New function.
+       (operator %): Likewise.
+       * selftest.h (ASSERT_KNOWN_EQ, ASSERT_KNOWN_EQ_AT, ASSERT_MAYBE_NE)
+       (ASSERT_MAYBE_NE_AT): New macros.
+
 2017-12-13  Eric Botcazou  <ebotcazou@adacore.com>
             Dominik Vogt  <vogt@linux.vnet.ibm.com>
 
index f6e59cde8dfec3b03ca86dafee623d0f0d22728f..115cbe53d0b25998207b19fe52303c72373351b0 100644 (file)
@@ -3162,7 +3162,7 @@ TEXI_GCCINT_FILES = gccint.texi gcc-common.texi gcc-vers.texi             \
         gnu.texi gpl_v3.texi fdl.texi contrib.texi languages.texi      \
         sourcebuild.texi gty.texi libgcc.texi cfg.texi tree-ssa.texi   \
         loop.texi generic.texi gimple.texi plugins.texi optinfo.texi   \
-        match-and-simplify.texi
+        match-and-simplify.texi poly-int.texi
 
 TEXI_GCCINSTALL_FILES = install.texi install-old.texi fdl.texi         \
         gcc-common.texi gcc-vers.texi
index 410583e1ce24f0ea22a92d165e9d450403b345f5..9d94e4922995d79a7093a619966b5592c555f94c 100644 (file)
@@ -396,6 +396,21 @@ typedef unsigned char uchar;
 #include "signop.h"
 #include "wide-int.h" 
 #include "wide-int-print.h"
+
+/* On targets that don't need polynomial offsets, target-specific code
+   should be able to treat poly_int like a normal constant, with a
+   conversion operator going from the former to the latter.  We also
+   allow this for gencondmd.c for all targets, so that we can treat
+   machine_modes as enums without causing build failures.  */
+#if (defined (IN_TARGET_CODE) \
+     && (defined (USE_ENUM_MODES) || NUM_POLY_INT_COEFFS == 1))
+#define POLY_INT_CONVERSION 1
+#else
+#define POLY_INT_CONVERSION 0
+#endif
+
+#include "poly-int.h"
+#include "poly-int-types.h"
 #include "insn-modes-inline.h"
 #include "machmode.h"
 #include "double-int.h"
index 817ed800cd214800e17bda13f335d6af5c9e8e6d..849c67c787ef825c932415280cba19a13f8fb36d 100644 (file)
@@ -107,6 +107,7 @@ Additional tutorial information is linked to from
 * Testsuites::      GCC testsuites.
 * Options::         Option specification files.
 * Passes::          Order of passes, what they do, and what each file is for.
+* poly_int::        Representation of runtime sizes and offsets.
 * GENERIC::         Language-independent representation generated by Front Ends
 * GIMPLE::          Tuple representation used by Tree SSA optimizers
 * Tree SSA::        Analysis and optimization of GIMPLE
@@ -144,6 +145,7 @@ Additional tutorial information is linked to from
 @include sourcebuild.texi
 @include options.texi
 @include passes.texi
+@include poly-int.texi
 @include generic.texi
 @include gimple.texi
 @include tree-ssa.texi
diff --git a/gcc/doc/poly-int.texi b/gcc/doc/poly-int.texi
new file mode 100644 (file)
index 0000000..1023e82
--- /dev/null
@@ -0,0 +1,1048 @@
+@node poly_int
+@chapter Sizes and offsets as runtime invariants
+@cindex polynomial integers
+@findex poly_int
+
+GCC allows the size of a hardware register to be a runtime invariant
+rather than a compile-time constant.  This in turn means that various
+sizes and offsets must also be runtime invariants rather than
+compile-time constants, such as:
+
+@itemize @bullet
+@item
+the size of a general @code{machine_mode} (@pxref{Machine Modes});
+
+@item
+the size of a spill slot;
+
+@item
+the offset of something within a stack frame;
+
+@item
+the number of elements in a vector;
+
+@item
+the size and offset of a @code{mem} rtx (@pxref{Regs and Memory}); and
+
+@item
+the byte offset in a @code{subreg} rtx (@pxref{Regs and Memory}).
+@end itemize
+
+The motivating example is the Arm SVE ISA, whose vector registers can be
+any multiple of 128 bits between 128 and 2048 inclusive.  The compiler
+normally produces code that works for all SVE register sizes, with the
+actual size only being known at runtime.
+
+GCC's main representation of such runtime invariants is the
+@code{poly_int} class.  This chapter describes what @code{poly_int}
+does, lists the available operations, and gives some general
+usage guidelines.
+
+@menu
+* Overview of @code{poly_int}::
+* Consequences of using @code{poly_int}::
+* Comparisons involving @code{poly_int}::
+* Arithmetic on @code{poly_int}s::
+* Alignment of @code{poly_int}s::
+* Computing bounds on @code{poly_int}s::
+* Converting @code{poly_int}s::
+* Miscellaneous @code{poly_int} routines::
+* Guidelines for using @code{poly_int}::
+@end menu
+
+@node Overview of @code{poly_int}
+@section Overview of @code{poly_int}
+
+@cindex @code{poly_int}, runtime value
+We define indeterminates @var{x1}, @dots{}, @var{xn} whose values are
+only known at runtime and use polynomials of the form:
+
+@smallexample
+@var{c0} + @var{c1} * @var{x1} + @dots{} + @var{cn} * @var{xn}
+@end smallexample
+
+to represent a size or offset whose value might depend on some
+of these indeterminates.  The coefficients @var{c0}, @dots{}, @var{cn}
+are always known at compile time, with the @var{c0} term being the
+``constant'' part that does not depend on any runtime value.
+
+GCC uses the @code{poly_int} class to represent these coefficients.
+The class has two template parameters: the first specifies the number of
+coefficients (@var{n} + 1) and the second specifies the type of the
+coefficients.  For example, @samp{poly_int<2, unsigned short>} represents
+a polynomial with two coefficients (and thus one indeterminate), with each
+coefficient having type @code{unsigned short}.  When @var{n} is 0,
+the class degenerates to a single compile-time constant @var{c0}.
+
+@cindex @code{poly_int}, template parameters
+@findex NUM_POLY_INT_COEFFS
+The number of coefficients needed for compilation is a fixed
+property of each target and is specified by the configuration macro
+@code{NUM_POLY_INT_COEFFS}.  The default value is 1, since most targets
+do not have such runtime invariants.  Targets that need a different
+value should @code{#define} the macro in their @file{@var{cpu}-modes.def}
+file.  @xref{Back End}.
+
+@cindex @code{poly_int}, invariant range
+@code{poly_int} makes the simplifying requirement that each indeterminate
+must be a nonnegative integer.  An indeterminate value of 0 should usually
+represent the minimum possible runtime value, with @var{c0} specifying
+the value in that case.
+
+For example, when targetting the Arm SVE ISA, the single indeterminate
+represents the number of 128-bit blocks in a vector @emph{beyond the minimum
+length of 128 bits}.  Thus the number of 64-bit doublewords in a vector
+is 2 + 2 * @var{x1}.  If an aggregate has a single SVE vector and 16
+additional bytes, its total size is 32 + 16 * @var{x1} bytes.
+
+The header file @file{poly-int-types.h} provides typedefs for the
+most common forms of @code{poly_int}, all having
+@code{NUM_POLY_INT_COEFFS} coefficients:
+
+@cindex @code{poly_int}, main typedefs
+@table @code
+@item poly_uint16
+a @samp{poly_int} with @code{unsigned short} coefficients.
+
+@item poly_int64
+a @samp{poly_int} with @code{HOST_WIDE_INT} coefficients.
+
+@item poly_uint64
+a @samp{poly_int} with @code{unsigned HOST_WIDE_INT} coefficients.
+
+@item poly_offset_int
+a @samp{poly_int} with @code{offset_int} coefficients.
+
+@item poly_wide_int
+a @samp{poly_int} with @code{wide_int} coefficients.
+
+@item poly_widest_int
+a @samp{poly_int} with @code{widest_int} coefficients.
+@end table
+
+Since the main purpose of @code{poly_int} is to represent sizes and
+offsets, the last two typedefs are only rarely used.
+
+@node Consequences of using @code{poly_int}
+@section Consequences of using @code{poly_int}
+
+The two main consequences of using polynomial sizes and offsets are that:
+
+@itemize
+@item
+there is no total ordering between the values at compile time, and
+
+@item
+some operations might yield results that cannot be expressed as a
+@code{poly_int}.
+@end itemize
+
+For example, if @var{x} is a runtime invariant, we cannot tell at
+compile time whether:
+
+@smallexample
+3 + 4@var{x} <= 1 + 5@var{x}
+@end smallexample
+
+since the condition is false when @var{x} <= 1 and true when @var{x} >= 2.
+
+Similarly, @code{poly_int} cannot represent the result of:
+
+@smallexample
+(3 + 4@var{x}) * (1 + 5@var{x})
+@end smallexample
+
+since it cannot (and in practice does not need to) store powers greater
+than one.  It also cannot represent the result of:
+
+@smallexample
+(3 + 4@var{x}) / (1 + 5@var{x})
+@end smallexample
+
+The following sections describe how we deal with these restrictions.
+
+@cindex @code{poly_int}, use in target-independent code
+As described earlier, a @code{poly_int<1, @var{T}>} has no indeterminates
+and so degenerates to a compile-time constant of type @var{T}.  It would
+be possible in that case to do all normal arithmetic on the @var{T},
+and to compare the @var{T} using the normal C++ operators.  We deliberately
+prevent target-independent code from doing this, since the compiler needs
+to support other @code{poly_int<@var{n}, @var{T}>} as well, regardless of
+the current target's @code{NUM_POLY_INT_COEFFS}.
+
+@cindex @code{poly_int}, use in target-specific code
+However, it would be very artificial to force target-specific code
+to follow these restrictions if the target has no runtime indeterminates.
+There is therefore an implicit conversion from @code{poly_int<1, @var{T}>}
+to @var{T} when compiling target-specific translation units.
+
+@node Comparisons involving @code{poly_int}
+@section Comparisons involving @code{poly_int}
+
+In general we need to compare sizes and offsets in two situations:
+those in which the values need to be ordered, and those in which
+the values can be unordered.  More loosely, the distinction is often
+between values that have a definite link (usually because they refer to the
+same underlying register or memory location) and values that have
+no definite link.  An example of the former is the relationship between
+the inner and outer sizes of a subreg, where we must know at compile time
+whether the subreg is paradoxical, partial, or complete.  An example of
+the latter is alias analysis: we might want to check whether two
+arbitrary memory references overlap.
+
+Referring back to the examples in the previous section, it makes sense
+to ask whether a memory reference of size @samp{3 + 4@var{x}} overlaps
+one of size @samp{1 + 5@var{x}}, but it does not make sense to have a
+subreg in which the outer mode has @samp{3 + 4@var{x}} bytes and the
+inner mode has @samp{1 + 5@var{x}} bytes (or vice versa).  Such subregs
+are always invalid and should trigger an internal compiler error
+if formed.
+
+The underlying operators are the same in both cases, but the distinction
+affects how they are used.
+
+@menu
+* Comparison functions for @code{poly_int}::
+* Properties of the @code{poly_int} comparisons::
+* Comparing potentially-unordered @code{poly_int}s::
+* Comparing ordered @code{poly_int}s::
+* Checking for a @code{poly_int} marker value::
+* Range checks on @code{poly_int}s::
+* Sorting @code{poly_int}s::
+@end menu
+
+@node Comparison functions for @code{poly_int}
+@subsection Comparison functions for @code{poly_int}
+
+@code{poly_int} provides the following routines for checking whether
+a particular condition ``may be'' (might be) true:
+
+@example
+maybe_lt maybe_le maybe_eq maybe_ge maybe_gt
+                  maybe_ne
+@end example
+
+The functions have their natural meaning:
+
+@table @samp
+@item maybe_lt(@var{a}, @var{b})
+Return true if @var{a} might be less than @var{b}.
+
+@item maybe_le(@var{a}, @var{b})
+Return true if @var{a} might be less than or equal to @var{b}.
+
+@item maybe_eq(@var{a}, @var{b})
+Return true if @var{a} might be equal to @var{b}.
+
+@item maybe_ne(@var{a}, @var{b})
+Return true if @var{a} might not be equal to @var{b}.
+
+@item maybe_ge(@var{a}, @var{b})
+Return true if @var{a} might be greater than or equal to @var{b}.
+
+@item maybe_gt(@var{a}, @var{b})
+Return true if @var{a} might be greater than @var{b}.
+@end table
+
+For readability, @code{poly_int} also provides ``known'' inverses of these
+functions:
+
+@example
+known_lt (@var{a}, @var{b}) == !maybe_ge (@var{a}, @var{b})
+known_le (@var{a}, @var{b}) == !maybe_gt (@var{a}, @var{b})
+known_eq (@var{a}, @var{b}) == !maybe_ne (@var{a}, @var{b})
+known_ge (@var{a}, @var{b}) == !maybe_lt (@var{a}, @var{b})
+known_gt (@var{a}, @var{b}) == !maybe_le (@var{a}, @var{b})
+known_ne (@var{a}, @var{b}) == !maybe_eq (@var{a}, @var{b})
+@end example
+
+@node Properties of the @code{poly_int} comparisons
+@subsection Properties of the @code{poly_int} comparisons
+
+All ``maybe'' relations except @code{maybe_ne} are transitive, so for example:
+
+@smallexample
+maybe_lt (@var{a}, @var{b}) && maybe_lt (@var{b}, @var{c}) implies maybe_lt (@var{a}, @var{c})
+@end smallexample
+
+for all @var{a}, @var{b} and @var{c}.  @code{maybe_lt}, @code{maybe_gt}
+and @code{maybe_ne} are irreflexive, so for example:
+
+@smallexample
+!maybe_lt (@var{a}, @var{a})
+@end smallexample
+
+is true for all @var{a}.  @code{maybe_le}, @code{maybe_eq} and @code{maybe_ge}
+are reflexive, so for example:
+
+@smallexample
+maybe_le (@var{a}, @var{a})
+@end smallexample
+
+is true for all @var{a}.  @code{maybe_eq} and @code{maybe_ne} are symmetric, so:
+
+@smallexample
+maybe_eq (@var{a}, @var{b}) == maybe_eq (@var{b}, @var{a})
+maybe_ne (@var{a}, @var{b}) == maybe_ne (@var{b}, @var{a})
+@end smallexample
+
+for all @var{a} and @var{b}.  In addition:
+
+@smallexample
+maybe_le (@var{a}, @var{b}) == maybe_lt (@var{a}, @var{b}) || maybe_eq (@var{a}, @var{b})
+maybe_ge (@var{a}, @var{b}) == maybe_gt (@var{a}, @var{b}) || maybe_eq (@var{a}, @var{b})
+maybe_lt (@var{a}, @var{b}) == maybe_gt (@var{b}, @var{a})
+maybe_le (@var{a}, @var{b}) == maybe_ge (@var{b}, @var{a})
+@end smallexample
+
+However:
+
+@smallexample
+maybe_le (@var{a}, @var{b}) && maybe_le (@var{b}, @var{a}) does not imply !maybe_ne (@var{a}, @var{b}) [== known_eq (@var{a}, @var{b})]
+maybe_ge (@var{a}, @var{b}) && maybe_ge (@var{b}, @var{a}) does not imply !maybe_ne (@var{a}, @var{b}) [== known_eq (@var{a}, @var{b})]
+@end smallexample
+
+One example is again @samp{@var{a} == 3 + 4@var{x}}
+and @samp{@var{b} == 1 + 5@var{x}}, where @samp{maybe_le (@var{a}, @var{b})},
+@samp{maybe_ge (@var{a}, @var{b})} and @samp{maybe_ne (@var{a}, @var{b})}
+all hold.  @code{maybe_le} and @code{maybe_ge} are therefore not antisymetric
+and do not form a partial order.
+
+From the above, it follows that:
+
+@itemize @bullet
+@item
+All ``known'' relations except @code{known_ne} are transitive.
+
+@item
+@code{known_lt}, @code{known_ne} and @code{known_gt} are irreflexive.
+
+@item
+@code{known_le}, @code{known_eq} and @code{known_ge} are reflexive.
+@end itemize
+
+Also:
+
+@smallexample
+known_lt (@var{a}, @var{b}) == known_gt (@var{b}, @var{a})
+known_le (@var{a}, @var{b}) == known_ge (@var{b}, @var{a})
+known_lt (@var{a}, @var{b}) implies !known_lt (@var{b}, @var{a})  [asymmetry]
+known_gt (@var{a}, @var{b}) implies !known_gt (@var{b}, @var{a})
+known_le (@var{a}, @var{b}) && known_le (@var{b}, @var{a}) == known_eq (@var{a}, @var{b}) [== !maybe_ne (@var{a}, @var{b})]
+known_ge (@var{a}, @var{b}) && known_ge (@var{b}, @var{a}) == known_eq (@var{a}, @var{b}) [== !maybe_ne (@var{a}, @var{b})]
+@end smallexample
+
+@code{known_le} and @code{known_ge} are therefore antisymmetric and are
+partial orders.  However:
+
+@smallexample
+known_le (@var{a}, @var{b}) does not imply known_lt (@var{a}, @var{b}) || known_eq (@var{a}, @var{b})
+known_ge (@var{a}, @var{b}) does not imply known_gt (@var{a}, @var{b}) || known_eq (@var{a}, @var{b})
+@end smallexample
+
+For example, @samp{known_le (4, 4 + 4@var{x})} holds because the runtime
+indeterminate @var{x} is a nonnegative integer, but neither
+@code{known_lt (4, 4 + 4@var{x})} nor @code{known_eq (4, 4 + 4@var{x})} hold.
+
+@node Comparing potentially-unordered @code{poly_int}s
+@subsection Comparing potentially-unordered @code{poly_int}s
+
+In cases where there is no definite link between two @code{poly_int}s,
+we can usually make a conservatively-correct assumption.  For example,
+the conservative assumption for alias analysis is that two references
+@emph{might} alias.
+
+One way of checking whether [@var{begin1}, @var{end1}) might overlap
+[@var{begin2}, @var{end2}) using the @code{poly_int} comparisons is:
+
+@smallexample
+maybe_gt (@var{end1}, @var{begin2}) && maybe_gt (@var{end2}, @var{begin1})
+@end smallexample
+
+and another (equivalent) way is:
+
+@smallexample
+!(known_le (@var{end1}, @var{begin2}) || known_le (@var{end2}, @var{begin1}))
+@end smallexample
+
+However, in this particular example, it is better to use the range helper
+functions instead.  @xref{Range checks on @code{poly_int}s}.
+
+@node Comparing ordered @code{poly_int}s
+@subsection Comparing ordered @code{poly_int}s
+
+In cases where there is a definite link between two @code{poly_int}s,
+such as the outer and inner sizes of subregs, we usually require the sizes
+to be ordered by the @code{known_le} partial order.  @code{poly_int} provides
+the following utility functions for ordered values:
+
+@table @samp
+@item ordered_p (@var{a}, @var{b})
+Return true if @var{a} and @var{b} are ordered by the @code{known_le}
+partial order.
+
+@item ordered_min (@var{a}, @var{b})
+Assert that @var{a} and @var{b} are ordered by @code{known_le} and return the
+minimum of the two.  When using this function, please add a comment explaining
+why the values are known to be ordered.
+
+@item ordered_max (@var{a}, @var{b})
+Assert that @var{a} and @var{b} are ordered by @code{known_le} and return the
+maximum of the two.  When using this function, please add a comment explaining
+why the values are known to be ordered.
+@end table
+
+For example, if a subreg has an outer mode of size @var{outer} and an
+inner mode of size @var{inner}:
+
+@itemize @bullet
+@item
+the subreg is complete if known_eq (@var{inner}, @var{outer})
+
+@item
+otherwise, the subreg is paradoxical if known_le (@var{inner}, @var{outer})
+
+@item
+otherwise, the subreg is partial if known_le (@var{outer}, @var{inner})
+
+@item
+otherwise, the subreg is ill-formed
+@end itemize
+
+Thus the subreg is only valid if
+@samp{ordered_p (@var{outer}, @var{inner})} is true.  If this condition
+is already known to be true then:
+
+@itemize @bullet
+@item
+the subreg is complete if known_eq (@var{inner}, @var{outer})
+
+@item
+the subreg is paradoxical if maybe_lt (@var{inner}, @var{outer})
+
+@item
+the subreg is partial if maybe_lt (@var{outer}, @var{inner})
+@end itemize
+
+with the three conditions being mutually exclusive.
+
+Code that checks whether a subreg is valid would therefore generally
+check whether @code{ordered_p} holds (in addition to whatever other
+checks are required for subreg validity).  Code that is dealing
+with existing subregs can assert that @code{ordered_p} holds
+and use either of the classifications above.
+
+@node Checking for a @code{poly_int} marker value
+@subsection Checking for a @code{poly_int} marker value
+
+It is sometimes useful to have a special ``marker value'' that is not
+meant to be taken literally.  For example, some code uses a size
+of -1 to represent an unknown size, rather than having to carry around
+a separate boolean to say whether the size is known.
+
+The best way of checking whether something is a marker value is
+@code{known_eq}.  Conversely the best way of checking whether something
+is @emph{not} a marker value is @code{maybe_ne}.
+
+Thus in the size example just mentioned, @samp{known_eq (size, -1)} would
+check for an unknown size and @samp{maybe_ne (size, -1)} would check for a
+known size.
+
+@node Range checks on @code{poly_int}s
+@subsection Range checks on @code{poly_int}s
+
+As well as the core comparisons
+(@pxref{Comparison functions for @code{poly_int}}), @code{poly_int} provides
+utilities for various kinds of range check.  In each case the range
+is represented by a start position and a size rather than a start
+position and an end position; this is because the former is used
+much more often than the latter in GCC@.  Also, the sizes can be
+-1 (or all ones for unsigned sizes) to indicate a range with a known
+start position but an unknown size.  All other sizes must be nonnegative.
+A range of size 0 does not contain anything or overlap anything.
+
+@table @samp
+@item known_size_p (@var{size})
+Return true if @var{size} represents a known range size, false if it
+is -1 or all ones (for signed and unsigned types respectively).
+
+@item ranges_maybe_overlap_p (@var{pos1}, @var{size1}, @var{pos2}, @var{size2})
+Return true if the range described by @var{pos1} and @var{size1} @emph{might}
+overlap the range described by @var{pos2} and @var{size2} (in other words,
+return true if we cannot prove that the ranges are disjoint).
+
+@item ranges_known_overlap_p (@var{pos1}, @var{size1}, @var{pos2}, @var{size2})
+Return true if the range described by @var{pos1} and @var{size1} is known to
+overlap the range described by @var{pos2} and @var{size2}.
+
+@item known_subrange_p (@var{pos1}, @var{size1}, @var{pos2}, @var{size2})
+Return true if the range described by @var{pos1} and @var{size1} is known to
+be contained in the range described by @var{pos2} and @var{size2}.
+
+@item maybe_in_range_p (@var{value}, @var{pos}, @var{size})
+Return true if @var{value} @emph{might} be in the range described by
+@var{pos} and @var{size} (in other words, return true if we cannot
+prove that @var{value} is outside that range).
+
+@item known_in_range_p (@var{value}, @var{pos}, @var{size})
+Return true if @var{value} is known to be in the range described
+by @var{pos} and @var{size}.
+
+@item endpoint_representable_p (@var{pos}, @var{size})
+Return true if the range described by @var{pos} and @var{size} is
+open-ended or if the endpoint (@var{pos} + @var{size}) is representable
+in the same type as @var{pos} and @var{size}.  The function returns false
+if adding @var{size} to @var{pos} makes conceptual sense but could overflow.
+@end table
+
+There is also a @code{poly_int} version of the @code{IN_RANGE_P} macro:
+
+@table @samp
+@item coeffs_in_range_p (@var{x}, @var{lower}, @var{upper})
+Return true if every coefficient of @var{x} is in the inclusive range
+[@var{lower}, @var{upper}].  This function can be useful when testing
+whether an operation would cause the values of coefficients to
+overflow.
+
+Note that the function does not indicate whether @var{x} itself is in the
+given range.  @var{x} can be either a constant or a @code{poly_int}.
+@end table
+
+@node Sorting @code{poly_int}s
+@subsection Sorting @code{poly_int}s
+
+@code{poly_int} provides the following routine for sorting:
+
+@table @samp
+@item compare_sizes_for_sort (@var{a}, @var{b})
+Compare @var{a} and @var{b} in reverse lexicographical order (that is,
+compare the highest-indexed coefficients first).  This can be useful when
+sorting data structures, since it has the effect of separating constant
+and non-constant values.  If all values are nonnegative, the constant
+values come first.
+
+Note that the values do not necessarily end up in numerical order.
+For example, @samp{1 + 1@var{x}} would come after @samp{100} in the sort order,
+but may well be less than @samp{100} at run time.
+@end table
+
+@node Arithmetic on @code{poly_int}s
+@section Arithmetic on @code{poly_int}s
+
+Addition, subtraction, negation and bit inversion all work normally for
+@code{poly_int}s.  Multiplication by a constant multiplier and left
+shifting by a constant shift amount also work normally.  General
+multiplication of two @code{poly_int}s is not supported and is not
+useful in practice.
+
+Other operations are only conditionally supported: the operation
+might succeed or might fail, depending on the inputs.
+
+This section describes both types of operation.
+
+@menu
+* Using @code{poly_int} with C++ arithmetic operators::
+* @code{wi} arithmetic on @code{poly_int}s::
+* Division of @code{poly_int}s::
+* Other @code{poly_int} arithmetic::
+@end menu
+
+@node Using @code{poly_int} with C++ arithmetic operators
+@subsection Using @code{poly_int} with C++ arithmetic operators
+
+The following C++ expressions are supported, where @var{p1} and @var{p2}
+are @code{poly_int}s and where @var{c1} and @var{c2} are scalars:
+
+@smallexample
+-@var{p1}
+~@var{p1}
+
+@var{p1} + @var{p2}
+@var{p1} + @var{c2}
+@var{c1} + @var{p2}
+
+@var{p1} - @var{p2}
+@var{p1} - @var{c2}
+@var{c1} - @var{p2}
+
+@var{c1} * @var{p2}
+@var{p1} * @var{c2}
+
+@var{p1} << @var{c2}
+
+@var{p1} += @var{p2}
+@var{p1} += @var{c2}
+
+@var{p1} -= @var{p2}
+@var{p1} -= @var{c2}
+
+@var{p1} *= @var{c2}
+@var{p1} <<= @var{c2}
+@end smallexample
+
+These arithmetic operations handle integer ranks in a similar way
+to C++.  The main difference is that every coefficient narrower than
+@code{HOST_WIDE_INT} promotes to @code{HOST_WIDE_INT}, whereas in
+C++ everything narrower than @code{int} promotes to @code{int}.
+For example:
+
+@smallexample
+poly_uint16     + int          -> poly_int64
+unsigned int    + poly_uint16  -> poly_int64
+poly_int64      + int          -> poly_int64
+poly_int32      + poly_uint64  -> poly_uint64
+uint64          + poly_int64   -> poly_uint64
+poly_offset_int + int32        -> poly_offset_int
+offset_int      + poly_uint16  -> poly_offset_int
+@end smallexample
+
+In the first two examples, both coefficients are narrower than
+@code{HOST_WIDE_INT}, so the result has coefficients of type
+@code{HOST_WIDE_INT}.  In the other examples, the coefficient
+with the highest rank ``wins''.
+
+If one of the operands is @code{wide_int} or @code{poly_wide_int},
+the rules are the same as for @code{wide_int} arithmetic.
+
+@node @code{wi} arithmetic on @code{poly_int}s
+@subsection @code{wi} arithmetic on @code{poly_int}s
+
+As well as the C++ operators, @code{poly_int} supports the following
+@code{wi} routines:
+
+@smallexample
+wi::neg (@var{p1}, &@var{overflow})
+
+wi::add (@var{p1}, @var{p2})
+wi::add (@var{p1}, @var{c2})
+wi::add (@var{c1}, @var{p1})
+wi::add (@var{p1}, @var{p2}, @var{sign}, &@var{overflow})
+
+wi::sub (@var{p1}, @var{p2})
+wi::sub (@var{p1}, @var{c2})
+wi::sub (@var{c1}, @var{p1})
+wi::sub (@var{p1}, @var{p2}, @var{sign}, &@var{overflow})
+
+wi::mul (@var{p1}, @var{c2})
+wi::mul (@var{c1}, @var{p1})
+wi::mul (@var{p1}, @var{c2}, @var{sign}, &@var{overflow})
+
+wi::lshift (@var{p1}, @var{c2})
+@end smallexample
+
+These routines just check whether overflow occurs on any individual
+coefficient; it is not possible to know at compile time whether the
+final runtime value would overflow.
+
+@node Division of @code{poly_int}s
+@subsection Division of @code{poly_int}s
+
+Division of @code{poly_int}s is possible for certain inputs.  The functions
+for division return true if the operation is possible and in most cases
+return the results by pointer.  The routines are:
+
+@table @samp
+@item multiple_p (@var{a}, @var{b})
+@itemx multiple_p (@var{a}, @var{b}, &@var{quotient})
+Return true if @var{a} is an exact multiple of @var{b}, storing the result
+in @var{quotient} if so.  There are overloads for various combinations
+of polynomial and constant @var{a}, @var{b} and @var{quotient}.
+
+@item constant_multiple_p (@var{a}, @var{b})
+@itemx constant_multiple_p (@var{a}, @var{b}, &@var{quotient})
+Like @code{multiple_p}, but also test whether the multiple is a
+compile-time constant.
+
+@item can_div_trunc_p (@var{a}, @var{b}, &@var{quotient})
+@itemx can_div_trunc_p (@var{a}, @var{b}, &@var{quotient}, &@var{remainder})
+Return true if we can calculate @samp{trunc (@var{a} / @var{b})} at compile
+time, storing the result in @var{quotient} and @var{remainder} if so.
+
+@item can_div_away_from_zero_p (@var{a}, @var{b}, &@var{quotient})
+Return true if we can calculate @samp{@var{a} / @var{b}} at compile time,
+rounding away from zero.  Store the result in @var{quotient} if so.
+
+Note that this is true if and only if @code{can_div_trunc_p} is true.
+The only difference is in the rounding of the result.
+@end table
+
+There is also an asserting form of division:
+
+@table @samp
+@item exact_div (@var{a}, @var{b})
+Assert that @var{a} is a multiple of @var{b} and return
+@samp{@var{a} / @var{b}}.  The result is a @code{poly_int} if @var{a}
+is a @code{poly_int}.
+@end table
+
+@node Other @code{poly_int} arithmetic
+@subsection Other @code{poly_int} arithmetic
+
+There are tentative routines for other operations besides division:
+
+@table @samp
+@item can_ior_p (@var{a}, @var{b}, &@var{result})
+Return true if we can calculate @samp{@var{a} | @var{b}} at compile time,
+storing the result in @var{result} if so.
+@end table
+
+Also, ANDs with a value @samp{(1 << @var{y}) - 1} or its inverse can be
+treated as alignment operations.  @xref{Alignment of @code{poly_int}s}.
+
+In addition, the following miscellaneous routines are available:
+
+@table @samp
+@item coeff_gcd (@var{a})
+Return the greatest common divisor of all nonzero coefficients in
+@var{a}, or zero if @var{a} is known to be zero.
+
+@item common_multiple (@var{a}, @var{b})
+Return a value that is a multiple of both @var{a} and @var{b}, where
+one value is a @code{poly_int} and the other is a scalar.  The result
+will be the least common multiple for some indeterminate values but
+not necessarily for all.
+
+@item force_common_multiple (@var{a}, @var{b})
+Return a value that is a multiple of both @code{poly_int} @var{a} and
+@code{poly_int} @var{b}, asserting that such a value exists.  The
+result will be the least common multiple for some indeterminate values
+but not necessarily for all.
+
+When using this routine, please add a comment explaining why the
+assertion is known to hold.
+@end table
+
+Please add any other operations that you find to be useful.
+
+@node Alignment of @code{poly_int}s
+@section Alignment of @code{poly_int}s
+
+@code{poly_int} provides various routines for aligning values and for querying
+misalignments.  In each case the alignment must be a power of 2.
+
+@table @samp
+@item can_align_p (@var{value}, @var{align})
+Return true if we can align @var{value} up or down to the nearest multiple
+of @var{align} at compile time.  The answer is the same for both directions.
+
+@item can_align_down (@var{value}, @var{align}, &@var{aligned})
+Return true if @code{can_align_p}; if so, set @var{aligned} to the greatest
+aligned value that is less than or equal to @var{value}.
+
+@item can_align_up (@var{value}, @var{align}, &@var{aligned})
+Return true if @code{can_align_p}; if so, set @var{aligned} to the lowest
+aligned value that is greater than or equal to @var{value}.
+
+@item known_equal_after_align_down (@var{a}, @var{b}, @var{align})
+Return true if we can align @var{a} and @var{b} down to the nearest
+@var{align} boundary at compile time and if the two results are equal.
+
+@item known_equal_after_align_up (@var{a}, @var{b}, @var{align})
+Return true if we can align @var{a} and @var{b} up to the nearest
+@var{align} boundary at compile time and if the two results are equal.
+
+@item aligned_lower_bound (@var{value}, @var{align})
+Return a result that is no greater than @var{value} and that is aligned
+to @var{align}.  The result will the closest aligned value for some
+indeterminate values but not necessarily for all.
+
+For example, suppose we are allocating an object of @var{size} bytes
+in a downward-growing stack whose current limit is given by @var{limit}.
+If the object requires @var{align} bytes of alignment, the new stack
+limit is given by:
+
+@smallexample
+aligned_lower_bound (@var{limit} - @var{size}, @var{align})
+@end smallexample
+
+@item aligned_upper_bound (@var{value}, @var{align})
+Likewise return a result that is no less than @var{value} and that is
+aligned to @var{align}.  This is the routine that would be used for
+upward-growing stacks in the scenario just described.
+
+@item known_misalignment (@var{value}, @var{align}, &@var{misalign})
+Return true if we can calculate the misalignment of @var{value}
+with respect to @var{align} at compile time, storing the result in
+@var{misalign} if so.
+
+@item known_alignment (@var{value})
+Return the minimum alignment that @var{value} is known to have
+(in other words, the largest alignment that can be guaranteed
+whatever the values of the indeterminates turn out to be).
+Return 0 if @var{value} is known to be 0.
+
+@item force_align_down (@var{value}, @var{align})
+Assert that @var{value} can be aligned down to @var{align} at compile
+time and return the result.  When using this routine, please add a
+comment explaining why the assertion is known to hold.
+
+@item force_align_up (@var{value}, @var{align})
+Likewise, but aligning up.
+
+@item force_align_down_and_div (@var{value}, @var{align})
+Divide the result of @code{force_align_down} by @var{align}.  Again,
+please add a comment explaining why the assertion in @code{force_align_down}
+is known to hold.
+
+@item force_align_up_and_div (@var{value}, @var{align})
+Likewise for @code{force_align_up}.
+
+@item force_get_misalignment (@var{value}, @var{align})
+Assert that we can calculate the misalignment of @var{value} with
+respect to @var{align} at compile time and return the misalignment.
+When using this function, please add a comment explaining why
+the assertion is known to hold.
+@end table
+
+@node Computing bounds on @code{poly_int}s
+@section Computing bounds on @code{poly_int}s
+
+@code{poly_int} also provides routines for calculating lower and upper bounds:
+
+@table @samp
+@item constant_lower_bound (@var{a})
+Assert that @var{a} is nonnegative and return the smallest value it can have.
+
+@item lower_bound (@var{a}, @var{b})
+Return a value that is always less than or equal to both @var{a} and @var{b}.
+It will be the greatest such value for some indeterminate values
+but necessarily for all.
+
+@item upper_bound (@var{a}, @var{b})
+Return a value that is always greater than or equal to both @var{a} and
+@var{b}.  It will be the least such value for some indeterminate values
+but necessarily for all.
+@end table
+
+@node Converting @code{poly_int}s
+@section Converting @code{poly_int}s
+
+A @code{poly_int<@var{n}, @var{T}>} can be constructed from up to
+@var{n} individual @var{T} coefficients, with the remaining coefficients
+being implicitly zero.  In particular, this means that every
+@code{poly_int<@var{n}, @var{T}>} can be constructed from a single
+scalar @var{T}, or something compatible with @var{T}.
+
+Also, a @code{poly_int<@var{n}, @var{T}>} can be constructed from
+a @code{poly_int<@var{n}, @var{U}>} if @var{T} can be constructed
+from @var{U}.
+
+The following functions provide other forms of conversion,
+or test whether such a conversion would succeed.
+
+@table @samp
+@item @var{value}.is_constant ()
+Return true if @code{poly_int} @var{value} is a compile-time constant.
+
+@item @var{value}.is_constant (&@var{c1})
+Return true if @code{poly_int} @var{value} is a compile-time constant,
+storing it in @var{c1} if so.  @var{c1} must be able to hold all
+constant values of @var{value} without loss of precision.
+
+@item @var{value}.to_constant ()
+Assert that @var{value} is a compile-time constant and return its value.
+When using this function, please add a comment explaining why the
+condition is known to hold (for example, because an earlier phase
+of analysis rejected non-constants).
+
+@item @var{value}.to_shwi (&@var{p2})
+Return true if @samp{poly_int<@var{N}, @var{T}>} @var{value} can be
+represented without loss of precision as a
+@samp{poly_int<@var{N}, @code{HOST_WIDE_INT}>}, storing it in that
+form in @var{p2} if so.
+
+@item @var{value}.to_uhwi (&@var{p2})
+Return true if @samp{poly_int<@var{N}, @var{T}>} @var{value} can be
+represented without loss of precision as a
+@samp{poly_int<@var{N}, @code{unsigned HOST_WIDE_INT}>}, storing it in that
+form in @var{p2} if so.
+
+@item @var{value}.force_shwi ()
+Forcibly convert each coefficient of @samp{poly_int<@var{N}, @var{T}>}
+@var{value} to @code{HOST_WIDE_INT}, truncating any that are out of range.
+Return the result as a @samp{poly_int<@var{N}, @code{HOST_WIDE_INT}>}.
+
+@item @var{value}.force_uhwi ()
+Forcibly convert each coefficient of @samp{poly_int<@var{N}, @var{T}>}
+@var{value} to @code{unsigned HOST_WIDE_INT}, truncating any that are
+out of range.  Return the result as a
+@samp{poly_int<@var{N}, @code{unsigned HOST_WIDE_INT}>}.
+
+@item wi::shwi (@var{value}, @var{precision})
+Return a @code{poly_int} with the same value as @var{value}, but with
+the coefficients converted from @code{HOST_WIDE_INT} to @code{wide_int}.
+@var{precision} specifies the precision of the @code{wide_int} cofficients;
+if this is wider than a @code{HOST_WIDE_INT}, the coefficients of
+@var{value} will be sign-extended to fit.
+
+@item wi::uhwi (@var{value}, @var{precision})
+Like @code{wi::shwi}, except that @var{value} has coefficients of
+type @code{unsigned HOST_WIDE_INT}.  If @var{precision} is wider than
+a @code{HOST_WIDE_INT}, the coefficients of @var{value} will be
+zero-extended to fit.
+
+@item wi::sext (@var{value}, @var{precision})
+Return a @code{poly_int} of the same type as @var{value}, sign-extending
+every coefficient from the low @var{precision} bits.  This in effect
+applies @code{wi::sext} to each coefficient individually.
+
+@item wi::zext (@var{value}, @var{precision})
+Like @code{wi::sext}, but for zero extension.
+
+@item poly_wide_int::from (@var{value}, @var{precision}, @var{sign})
+Convert @var{value} to a @code{poly_wide_int} in which each coefficient
+has @var{precision} bits.  Extend the coefficients according to
+@var{sign} if the coefficients have fewer bits.
+
+@item poly_offset_int::from (@var{value}, @var{sign})
+Convert @var{value} to a @code{poly_offset_int}, extending its coefficients
+according to @var{sign} if they have fewer bits than @code{offset_int}.
+
+@item poly_widest_int::from (@var{value}, @var{sign})
+Convert @var{value} to a @code{poly_widest_int}, extending its coefficients
+according to @var{sign} if they have fewer bits than @code{widest_int}.
+@end table
+
+@node Miscellaneous @code{poly_int} routines
+@section Miscellaneous @code{poly_int} routines
+
+@table @samp
+@item print_dec (@var{value}, @var{file}, @var{sign})
+@itemx print_dec (@var{value}, @var{file})
+Print @var{value} to @var{file} as a decimal value, interpreting
+the coefficients according to @var{sign}.  The final argument is
+optional if @var{value} has an inherent sign; for example,
+@code{poly_int64} values print as signed by default and
+@code{poly_uint64} values print as unsigned by default.
+
+This is a simply a @code{poly_int} version of a wide-int routine.
+@end table
+
+@node Guidelines for using @code{poly_int}
+@section Guidelines for using @code{poly_int}
+
+One of the main design goals of @code{poly_int} was to make it easy
+to write target-independent code that handles variable-sized registers
+even when the current target has fixed-sized registers.  There are two
+aspects to this:
+
+@itemize
+@item
+The set of @code{poly_int} operations should be complete enough that
+the question in most cases becomes ``Can we do this operation on these
+particular @code{poly_int} values?  If not, bail out'' rather than
+``Are these @code{poly_int} values constant?  If so, do the operation,
+otherwise bail out''.
+
+@item
+If target-independent code compiles and runs correctly on a target
+with one value of @code{NUM_POLY_INT_COEFFS}, and if the code does not
+use asserting functions like @code{to_constant}, it is reasonable to
+assume that the code also works on targets with other values of
+@code{NUM_POLY_INT_COEFFS}.  There is no need to check this during
+everyday development.
+@end itemize
+
+So the general principle is: if target-independent code is dealing
+with a @code{poly_int} value, it is better to operate on it as a
+@code{poly_int} if at all possible, choosing conservatively-correct
+behavior if a particular operation fails.  For example, the following
+code handles an index @code{pos} into a sequence of vectors that each
+have @code{nunits} elements:
+
+@smallexample
+/* Calculate which vector contains the result, and which lane of
+   that vector we need.  */
+if (!can_div_trunc_p (pos, nunits, &vec_entry, &vec_index))
+  @{
+    if (dump_enabled_p ())
+      dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+                       "Cannot determine which vector holds the"
+                       " final result.\n");
+    return false;
+  @}
+@end smallexample
+
+However, there are some contexts in which operating on a
+@code{poly_int} is not possible or does not make sense.  One example
+is when handling static initializers, since no current target supports
+the concept of a variable-length static initializer.  In these
+situations, a reasonable fallback is:
+
+@smallexample
+if (@var{poly_value}.is_constant (&@var{const_value}))
+  @{
+    @dots{}
+    /* Operate on @var{const_value}.  */
+    @dots{}
+  @}
+else
+  @{
+    @dots{}
+    /* Conservatively correct fallback.  */
+    @dots{}
+  @}
+@end smallexample
+
+@code{poly_int} also provides some asserting functions like
+@code{to_constant}.  Please only use these functions if there is a
+good theoretical reason to believe that the assertion cannot fire.
+For example, if some work is divided into an analysis phase and an
+implementation phase, the analysis phase might reject inputs that are
+not @code{is_constant}, in which case the implementation phase can
+reasonably use @code{to_constant} on the remaining inputs.  The assertions
+should not be used to discover whether a condition ever occurs ``in the
+field''; in other words, they should not be used to restrict code to
+constants at first, with the intention of only implementing a
+@code{poly_int} version if a user hits the assertion.
+
+If a particular asserting function like @code{to_constant} is needed
+more than once for the same reason, it is probably worth adding a
+helper function or macro for that situation, so that the justification
+only needs to be given once.  For example:
+
+@smallexample
+/* Return the size of an element in a vector of size SIZE, given that
+   the vector has NELTS elements.  The return value is in the same units
+   as SIZE (either bits or bytes).
+
+   to_constant () is safe in this situation because vector elements are
+   always constant-sized scalars.  */
+#define vector_element_size(SIZE, NELTS) \
+  (exact_div (SIZE, NELTS).to_constant ())
+@end smallexample
+
+Target-specific code in @file{config/@var{cpu}} only needs to handle
+non-constant @code{poly_int}s if @code{NUM_POLY_INT_COEFFS} is greater
+than one.  For other targets, @code{poly_int} degenerates to a compile-time
+constant and is often interchangable with a normal scalar integer.
+There are two main exceptions:
+
+@itemize
+@item
+Sometimes an explicit cast to an integer type might be needed, such as to
+resolve ambiguities in a @code{?:} expression, or when passing values
+through @code{...} to things like print functions.
+
+@item
+Target macros are included in target-independent code and so do not
+have access to the implicit conversion to a scalar integer.
+If this becomes a problem for a particular target macro, the
+possible solutions, in order of preference, are:
+
+@itemize
+@item
+Convert the target macro to a target hook (for all targets).
+
+@item
+Put the target's implementation of the target macro in its
+@file{@var{cpu}.c} file and call it from the target macro in the
+@file{@var{cpu}.h} file.
+
+@item
+Add @code{to_constant ()} calls where necessary.  The previous option
+is preferable because it will help with any future conversion of the
+macro to a hook.
+@end itemize
+@end itemize
+
index dd3c0d3cfc1ec80612391102898fd04eeaf3e234..c28bdd5149bc8e5a997619e3b03d7028f4df0b8f 100644 (file)
@@ -2067,6 +2067,15 @@ TARGET_CAN_CHANGE_MODE_CLASS (@var{m2}, @var{m1}, @var{class})
 
 must be false for every class @var{class} that includes @var{reg}.
 
+GCC must be able to determine at compile time whether a subreg is
+paradoxical, whether it occupies a whole number of blocks, or whether
+it is a lowpart of a block.  This means that certain combinations of
+variable-sized mode are not permitted.  For example, if @var{m2}
+holds @var{n} @code{SI} values, where @var{n} is greater than zero,
+it is not possible to form a @code{DI} @code{subreg} of it; such a
+@code{subreg} would be paradoxical when @var{n} is 1 but not when
+@var{n} is greater than 1.
+
 @findex SUBREG_REG
 @findex SUBREG_BYTE
 The first operand of a @code{subreg} expression is customarily accessed
index b39c7efa415000551febb5ac596f19d30e4f84e7..45675e38d71cd351532ece56a003767721be87f2 100644 (file)
@@ -6725,6 +6725,12 @@ delay slot branches filled using the basic filler is often still desirable
 as the delay slot can hide a pipeline bubble.
 @end deftypefn
 
+@deftypefn {Target Hook} HOST_WIDE_INT TARGET_ESTIMATED_POLY_VALUE (poly_int64 @var{val})
+Return an estimate of the runtime value of @var{val}, for use in
+things like cost calculations or profiling frequencies.  The default
+implementation returns the lowest possible value of @var{val}.
+@end deftypefn
+
 @node Scheduling
 @section Adjusting the Instruction Scheduler
 
index 57b83a8e5428290c1022ec6c51a767ccfd99a8fb..ff0067360cdfc295f12494f6b15ecc378aa61ff8 100644 (file)
@@ -4607,6 +4607,8 @@ Define this macro if a non-short-circuit operation produced by
 
 @hook TARGET_NO_SPECULATION_IN_DELAY_SLOTS_P
 
+@hook TARGET_ESTIMATED_POLY_VALUE
+
 @node Scheduling
 @section Adjusting the Instruction Scheduler
 
index 4eb8ee56d8808fd59298cdc26ed83b055af2bd2b..e7ee3ab1ad0f6e4c4da5e851fdfdb0a69a471a0c 100644 (file)
@@ -781,6 +781,10 @@ create_modes (void)
 #endif
 }
 
+#ifndef NUM_POLY_INT_COEFFS
+#define NUM_POLY_INT_COEFFS 1
+#endif
+
 /* Processing.  */
 
 /* Sort a list of modes into the order needed for the WIDER field:
@@ -1246,6 +1250,8 @@ enum machine_mode\n{");
 
   printf ("#define NUM_INT_N_ENTS %d\n", n_int_n_ents);
 
+  printf ("#define NUM_POLY_INT_COEFFS %d\n", NUM_POLY_INT_COEFFS);
+
   puts ("\
 \n\
 #endif /* insn-modes.h */");
diff --git a/gcc/poly-int-types.h b/gcc/poly-int-types.h
new file mode 100644 (file)
index 0000000..1c62ff8
--- /dev/null
@@ -0,0 +1,83 @@
+/* Typedefs for polynomial integers used in GCC.
+   Copyright (C) 2016-2017 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 HAVE_POLY_INT_TYPES_H
+#define HAVE_POLY_INT_TYPES_H
+
+typedef poly_int_pod<NUM_POLY_INT_COEFFS, unsigned short> poly_uint16_pod;
+typedef poly_int_pod<NUM_POLY_INT_COEFFS, HOST_WIDE_INT> poly_int64_pod;
+typedef poly_int_pod<NUM_POLY_INT_COEFFS,
+                    unsigned HOST_WIDE_INT> poly_uint64_pod;
+typedef poly_int_pod<NUM_POLY_INT_COEFFS, offset_int> poly_offset_int_pod;
+typedef poly_int_pod<NUM_POLY_INT_COEFFS, wide_int> poly_wide_int_pod;
+typedef poly_int_pod<NUM_POLY_INT_COEFFS, widest_int> poly_widest_int_pod;
+
+typedef poly_int<NUM_POLY_INT_COEFFS, unsigned short> poly_uint16;
+typedef poly_int<NUM_POLY_INT_COEFFS, HOST_WIDE_INT> poly_int64;
+typedef poly_int<NUM_POLY_INT_COEFFS, unsigned HOST_WIDE_INT> poly_uint64;
+typedef poly_int<NUM_POLY_INT_COEFFS, offset_int> poly_offset_int;
+typedef poly_int<NUM_POLY_INT_COEFFS, wide_int> poly_wide_int;
+typedef poly_int<NUM_POLY_INT_COEFFS, wide_int_ref> poly_wide_int_ref;
+typedef poly_int<NUM_POLY_INT_COEFFS, widest_int> poly_widest_int;
+
+/* Divide bit quantity X by BITS_PER_UNIT and round down (towards -Inf).
+   If X is a bit size, this gives the number of whole bytes spanned by X.
+
+   This is safe because non-constant mode sizes must be a whole number
+   of bytes in size.  */
+#define bits_to_bytes_round_down(X) force_align_down_and_div (X, BITS_PER_UNIT)
+
+/* Divide bit quantity X by BITS_PER_UNIT and round up (towards +Inf).
+   If X is a bit size, this gives the number of whole or partial bytes
+   spanned by X.
+
+   This is safe because non-constant mode sizes must be a whole number
+   of bytes in size.  */
+#define bits_to_bytes_round_up(X) force_align_up_and_div (X, BITS_PER_UNIT)
+
+/* Return the number of bits in bit quantity X that do not belong to
+   whole bytes.  This is equivalent to:
+
+       X - bits_to_bytes_round_down (X) * BITS_PER_UNIT
+
+   This is safe because non-constant mode sizes must be a whole number
+   of bytes in size.  */
+#define num_trailing_bits(X) force_get_misalignment (X, BITS_PER_UNIT)
+
+/* Return the size of an element in a vector of size SIZE, given that
+   the vector has NELTS elements.  The return value is in the same units
+   as SIZE (either bits or bytes).
+
+   to_constant () is safe in this situation because vector elements are
+   always constant-sized scalars.  */
+#define vector_element_size(SIZE, NELTS) \
+  (exact_div (SIZE, NELTS).to_constant ())
+
+/* Wrapper for poly_int arguments to target macros, so that if a target
+   doesn't need polynomial-sized modes, its header file can continue to
+   treat the argument as a normal constant.  This should go away once
+   macros are moved to target hooks.  It shouldn't be used in other
+   contexts.  */
+#if NUM_POLY_INT_COEFFS == 1
+#define MACRO_INT(X) ((X).to_constant ())
+#else
+#define MACRO_INT(X) (X)
+#endif
+
+#endif
diff --git a/gcc/poly-int.h b/gcc/poly-int.h
new file mode 100644 (file)
index 0000000..8472e51
--- /dev/null
@@ -0,0 +1,2601 @@
+/* Polynomial integer classes.
+   Copyright (C) 2014-2017 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/>.  */
+
+/* This file provides a representation of sizes and offsets whose exact
+   values depend on certain runtime properties.  The motivating example
+   is the Arm SVE ISA, in which the number of vector elements is only
+   known at runtime.  See doc/poly-int.texi for more details.
+
+   Tests for poly-int.h are located in testsuite/gcc.dg/plugin,
+   since they are too expensive (in terms of binary size) to be
+   included as selftests.  */
+
+#ifndef HAVE_POLY_INT_H
+#define HAVE_POLY_INT_H
+
+template<unsigned int N, typename T> class poly_int_pod;
+template<unsigned int N, typename T> class poly_int;
+
+/* poly_coeff_traiits<T> describes the properties of a poly_int
+   coefficient type T:
+
+   - poly_coeff_traits<T1>::rank is less than poly_coeff_traits<T2>::rank
+     if T1 can promote to T2.  For C-like types the rank is:
+
+       (2 * number of bytes) + (unsigned ? 1 : 0)
+
+     wide_ints don't have a normal rank and so use a value of INT_MAX.
+     Any fixed-width integer should be promoted to wide_int if possible
+     and lead to an error otherwise.
+
+   - poly_coeff_traits<T>::int_type is the type to which an integer
+     literal should be cast before comparing it with T.
+
+   - poly_coeff_traits<T>::precision is the number of bits that T can hold.
+
+   - poly_coeff_traits<T>::signedness is:
+       0 if T is unsigned
+       1 if T is signed
+       -1 if T has no inherent sign (as for wide_int).
+
+   - poly_coeff_traits<T>::max_value, if defined, is the maximum value of T.
+
+   - poly_coeff_traits<T>::result is a type that can hold results of
+     operations on T.  This is different from T itself in cases where T
+     is the result of an accessor like wi::to_offset.  */
+template<typename T, wi::precision_type = wi::int_traits<T>::precision_type>
+struct poly_coeff_traits;
+
+template<typename T>
+struct poly_coeff_traits<T, wi::FLEXIBLE_PRECISION>
+{
+  typedef T result;
+  typedef T int_type;
+  static const int signedness = (T (0) >= T (-1));
+  static const int precision = sizeof (T) * CHAR_BIT;
+  static const T max_value = (signedness
+                             ? ((T (1) << (precision - 2))
+                                + ((T (1) << (precision - 2)) - 1))
+                             : T (-1));
+  static const int rank = sizeof (T) * 2 + !signedness;
+};
+
+template<typename T>
+struct poly_coeff_traits<T, wi::VAR_PRECISION>
+{
+  typedef T result;
+  typedef int int_type;
+  static const int signedness = -1;
+  static const int precision = WIDE_INT_MAX_PRECISION;
+  static const int rank = INT_MAX;
+};
+
+template<typename T>
+struct poly_coeff_traits<T, wi::CONST_PRECISION>
+{
+  typedef WI_UNARY_RESULT (T) result;
+  typedef int int_type;
+  /* These types are always signed.  */
+  static const int signedness = 1;
+  static const int precision = wi::int_traits<T>::precision;
+  static const int rank = precision * 2 / CHAR_BIT;
+};
+
+/* Information about a pair of coefficient types.  */
+template<typename T1, typename T2>
+struct poly_coeff_pair_traits
+{
+  /* True if T1 can represent all the values of T2.
+
+     Either:
+
+     - T1 should be a type with the same signedness as T2 and no less
+       precision.  This allows things like int16_t -> int16_t and
+       uint32_t -> uint64_t.
+
+     - T1 should be signed, T2 should be unsigned, and T1 should be
+       wider than T2.  This allows things like uint16_t -> int32_t.
+
+     This rules out cases in which T1 has less precision than T2 or where
+     the conversion would reinterpret the top bit.  E.g. int16_t -> uint32_t
+     can be dangerous and should have an explicit cast if deliberate.  */
+  static const bool lossless_p = (poly_coeff_traits<T1>::signedness
+                                 == poly_coeff_traits<T2>::signedness
+                                 ? (poly_coeff_traits<T1>::precision
+                                    >= poly_coeff_traits<T2>::precision)
+                                 : (poly_coeff_traits<T1>::signedness == 1
+                                    && poly_coeff_traits<T2>::signedness == 0
+                                    && (poly_coeff_traits<T1>::precision
+                                        > poly_coeff_traits<T2>::precision)));
+
+  /* 0 if T1 op T2 should promote to HOST_WIDE_INT,
+     1 if T1 op T2 should promote to unsigned HOST_WIDE_INT,
+     2 if T1 op T2 should use wide-int rules.  */
+#define RANK(X) poly_coeff_traits<X>::rank
+  static const int result_kind
+    = ((RANK (T1) <= RANK (HOST_WIDE_INT)
+       && RANK (T2) <= RANK (HOST_WIDE_INT))
+       ? 0
+       : (RANK (T1) <= RANK (unsigned HOST_WIDE_INT)
+         && RANK (T2) <= RANK (unsigned HOST_WIDE_INT))
+       ? 1 : 2);
+#undef RANK
+};
+
+/* SFINAE class that makes T3 available as "type" if T2 can represent all the
+   values in T1.  */
+template<typename T1, typename T2, typename T3,
+        bool lossless_p = poly_coeff_pair_traits<T1, T2>::lossless_p>
+struct if_lossless;
+template<typename T1, typename T2, typename T3>
+struct if_lossless<T1, T2, T3, true>
+{
+  typedef T3 type;
+};
+
+/* poly_int_traits<T> describes an integer type T that might be polynomial
+   or non-polynomial:
+
+   - poly_int_traits<T>::is_poly is true if T is a poly_int-based type
+     and false otherwise.
+
+   - poly_int_traits<T>::num_coeffs gives the number of coefficients in T
+     if T is a poly_int and 1 otherwise.
+
+   - poly_int_traits<T>::coeff_type gives the coefficent type of T if T
+     is a poly_int and T itself otherwise
+
+   - poly_int_traits<T>::int_type is a shorthand for
+     typename poly_coeff_traits<coeff_type>::int_type.  */
+template<typename T>
+struct poly_int_traits
+{
+  static const bool is_poly = false;
+  static const unsigned int num_coeffs = 1;
+  typedef T coeff_type;
+  typedef typename poly_coeff_traits<T>::int_type int_type;
+};
+template<unsigned int N, typename C>
+struct poly_int_traits<poly_int_pod<N, C> >
+{
+  static const bool is_poly = true;
+  static const unsigned int num_coeffs = N;
+  typedef C coeff_type;
+  typedef typename poly_coeff_traits<C>::int_type int_type;
+};
+template<unsigned int N, typename C>
+struct poly_int_traits<poly_int<N, C> > : poly_int_traits<poly_int_pod<N, C> >
+{
+};
+
+/* SFINAE class that makes T2 available as "type" if T1 is a non-polynomial
+   type.  */
+template<typename T1, typename T2 = T1,
+        bool is_poly = poly_int_traits<T1>::is_poly>
+struct if_nonpoly {};
+template<typename T1, typename T2>
+struct if_nonpoly<T1, T2, false>
+{
+  typedef T2 type;
+};
+
+/* SFINAE class that makes T3 available as "type" if both T1 and T2 are
+   non-polynomial types.  */
+template<typename T1, typename T2, typename T3,
+        bool is_poly1 = poly_int_traits<T1>::is_poly,
+        bool is_poly2 = poly_int_traits<T2>::is_poly>
+struct if_nonpoly2 {};
+template<typename T1, typename T2, typename T3>
+struct if_nonpoly2<T1, T2, T3, false, false>
+{
+  typedef T3 type;
+};
+
+/* SFINAE class that makes T2 available as "type" if T1 is a polynomial
+   type.  */
+template<typename T1, typename T2 = T1,
+        bool is_poly = poly_int_traits<T1>::is_poly>
+struct if_poly {};
+template<typename T1, typename T2>
+struct if_poly<T1, T2, true>
+{
+  typedef T2 type;
+};
+
+/* poly_result<T1, T2> describes the result of an operation on two
+   types T1 and T2, where at least one of the types is polynomial:
+
+   - poly_result<T1, T2>::type gives the result type for the operation.
+     The intention is to provide normal C-like rules for integer ranks,
+     except that everything smaller than HOST_WIDE_INT promotes to
+     HOST_WIDE_INT.
+
+   - poly_result<T1, T2>::cast is the type to which an operand of type
+     T1 should be cast before doing the operation, to ensure that
+     the operation is done at the right precision.  Casting to
+     poly_result<T1, T2>::type would also work, but casting to this
+     type is more efficient.  */
+template<typename T1, typename T2 = T1,
+        int result_kind = poly_coeff_pair_traits<T1, T2>::result_kind>
+struct poly_result;
+
+/* Promote pair to HOST_WIDE_INT.  */
+template<typename T1, typename T2>
+struct poly_result<T1, T2, 0>
+{
+  typedef HOST_WIDE_INT type;
+  /* T1 and T2 are primitive types, so cast values to T before operating
+     on them.  */
+  typedef type cast;
+};
+
+/* Promote pair to unsigned HOST_WIDE_INT.  */
+template<typename T1, typename T2>
+struct poly_result<T1, T2, 1>
+{
+  typedef unsigned HOST_WIDE_INT type;
+  /* T1 and T2 are primitive types, so cast values to T before operating
+     on them.  */
+  typedef type cast;
+};
+
+/* Use normal wide-int rules.  */
+template<typename T1, typename T2>
+struct poly_result<T1, T2, 2>
+{
+  typedef WI_BINARY_RESULT (T1, T2) type;
+  /* Don't cast values before operating on them; leave the wi:: routines
+     to handle promotion as necessary.  */
+  typedef const T1 &cast;
+};
+
+/* The coefficient type for the result of a binary operation on two
+   poly_ints, the first of which has coefficients of type C1 and the
+   second of which has coefficients of type C2.  */
+#define POLY_POLY_COEFF(C1, C2) typename poly_result<C1, C2>::type
+
+/* Enforce that T2 is non-polynomial and provide the cofficient type of
+   the result of a binary operation in which the first operand is a
+   poly_int with coefficients of type C1 and the second operand is
+   a constant of type T2.  */
+#define POLY_CONST_COEFF(C1, T2) \
+  POLY_POLY_COEFF (C1, typename if_nonpoly<T2>::type)
+
+/* Likewise in reverse.  */
+#define CONST_POLY_COEFF(T1, C2) \
+  POLY_POLY_COEFF (typename if_nonpoly<T1>::type, C2)
+
+/* The result type for a binary operation on poly_int<N, C1> and
+   poly_int<N, C2>.  */
+#define POLY_POLY_RESULT(N, C1, C2) poly_int<N, POLY_POLY_COEFF (C1, C2)>
+
+/* Enforce that T2 is non-polynomial and provide the result type
+   for a binary operation on poly_int<N, C1> and T2.  */
+#define POLY_CONST_RESULT(N, C1, T2) poly_int<N, POLY_CONST_COEFF (C1, T2)>
+
+/* Enforce that T1 is non-polynomial and provide the result type
+   for a binary operation on T1 and poly_int<N, C2>.  */
+#define CONST_POLY_RESULT(N, T1, C2) poly_int<N, CONST_POLY_COEFF (T1, C2)>
+
+/* Enforce that T1 and T2 are non-polynomial and provide the result type
+   for a binary operation on T1 and T2.  */
+#define CONST_CONST_RESULT(N, T1, T2) \
+  POLY_POLY_COEFF (typename if_nonpoly<T1>::type, \
+                  typename if_nonpoly<T2>::type)
+
+/* The type to which a coefficient of type C1 should be cast before
+   using it in a binary operation with a coefficient of type C2.  */
+#define POLY_CAST(C1, C2) typename poly_result<C1, C2>::cast
+
+/* Provide the coefficient type for the result of T1 op T2, where T1
+   and T2 can be polynomial or non-polynomial.  */
+#define POLY_BINARY_COEFF(T1, T2) \
+  typename poly_result<typename poly_int_traits<T1>::coeff_type, \
+                      typename poly_int_traits<T2>::coeff_type>::type
+
+/* The type to which an integer constant should be cast before
+   comparing it with T.  */
+#define POLY_INT_TYPE(T) typename poly_int_traits<T>::int_type
+
+/* RES is a poly_int result that has coefficients of type C and that
+   is being built up a coefficient at a time.  Set coefficient number I
+   to VALUE in the most efficient way possible.
+
+   For primitive C it is better to assign directly, since it avoids
+   any further calls and so is more efficient when the compiler is
+   built at -O0.  But for wide-int based C it is better to construct
+   the value in-place.  This means that calls out to a wide-int.cc
+   routine can take the address of RES rather than the address of
+   a temporary.
+
+   The dummy comparison against a null C * is just a way of checking
+   that C gives the right type.  */
+#define POLY_SET_COEFF(C, RES, I, VALUE) \
+  ((void) (&(RES).coeffs[0] == (C *) 0), \
+   wi::int_traits<C>::precision_type == wi::FLEXIBLE_PRECISION \
+   ? (void) ((RES).coeffs[I] = VALUE) \
+   : (void) ((RES).coeffs[I].~C (), new (&(RES).coeffs[I]) C (VALUE)))
+
+/* A base POD class for polynomial integers.  The polynomial has N
+   coefficients of type C.  */
+template<unsigned int N, typename C>
+class poly_int_pod
+{
+public:
+  template<typename Ca>
+  poly_int_pod &operator = (const poly_int_pod<N, Ca> &);
+  template<typename Ca>
+  typename if_nonpoly<Ca, poly_int_pod>::type &operator = (const Ca &);
+
+  template<typename Ca>
+  poly_int_pod &operator += (const poly_int_pod<N, Ca> &);
+  template<typename Ca>
+  typename if_nonpoly<Ca, poly_int_pod>::type &operator += (const Ca &);
+
+  template<typename Ca>
+  poly_int_pod &operator -= (const poly_int_pod<N, Ca> &);
+  template<typename Ca>
+  typename if_nonpoly<Ca, poly_int_pod>::type &operator -= (const Ca &);
+
+  template<typename Ca>
+  typename if_nonpoly<Ca, poly_int_pod>::type &operator *= (const Ca &);
+
+  poly_int_pod &operator <<= (unsigned int);
+
+  bool is_constant () const;
+
+  template<typename T>
+  typename if_lossless<T, C, bool>::type is_constant (T *) const;
+
+  C to_constant () const;
+
+  template<typename Ca>
+  static poly_int<N, C> from (const poly_int_pod<N, Ca> &, unsigned int,
+                             signop);
+  template<typename Ca>
+  static poly_int<N, C> from (const poly_int_pod<N, Ca> &, signop);
+
+  bool to_shwi (poly_int_pod<N, HOST_WIDE_INT> *) const;
+  bool to_uhwi (poly_int_pod<N, unsigned HOST_WIDE_INT> *) const;
+  poly_int<N, HOST_WIDE_INT> force_shwi () const;
+  poly_int<N, unsigned HOST_WIDE_INT> force_uhwi () const;
+
+#if POLY_INT_CONVERSION
+  operator C () const;
+#endif
+
+  C coeffs[N];
+};
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline poly_int_pod<N, C>&
+poly_int_pod<N, C>::operator = (const poly_int_pod<N, Ca> &a)
+{
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, *this, i, a.coeffs[i]);
+  return *this;
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline typename if_nonpoly<Ca, poly_int_pod<N, C> >::type &
+poly_int_pod<N, C>::operator = (const Ca &a)
+{
+  POLY_SET_COEFF (C, *this, 0, a);
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      POLY_SET_COEFF (C, *this, i, wi::ints_for<C>::zero (this->coeffs[0]));
+  return *this;
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline poly_int_pod<N, C>&
+poly_int_pod<N, C>::operator += (const poly_int_pod<N, Ca> &a)
+{
+  for (unsigned int i = 0; i < N; i++)
+    this->coeffs[i] += a.coeffs[i];
+  return *this;
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline typename if_nonpoly<Ca, poly_int_pod<N, C> >::type &
+poly_int_pod<N, C>::operator += (const Ca &a)
+{
+  this->coeffs[0] += a;
+  return *this;
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline poly_int_pod<N, C>&
+poly_int_pod<N, C>::operator -= (const poly_int_pod<N, Ca> &a)
+{
+  for (unsigned int i = 0; i < N; i++)
+    this->coeffs[i] -= a.coeffs[i];
+  return *this;
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline typename if_nonpoly<Ca, poly_int_pod<N, C> >::type &
+poly_int_pod<N, C>::operator -= (const Ca &a)
+{
+  this->coeffs[0] -= a;
+  return *this;
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline typename if_nonpoly<Ca, poly_int_pod<N, C> >::type &
+poly_int_pod<N, C>::operator *= (const Ca &a)
+{
+  for (unsigned int i = 0; i < N; i++)
+    this->coeffs[i] *= a;
+  return *this;
+}
+
+template<unsigned int N, typename C>
+inline poly_int_pod<N, C>&
+poly_int_pod<N, C>::operator <<= (unsigned int a)
+{
+  for (unsigned int i = 0; i < N; i++)
+    this->coeffs[i] <<= a;
+  return *this;
+}
+
+/* Return true if the polynomial value is a compile-time constant.  */
+
+template<unsigned int N, typename C>
+inline bool
+poly_int_pod<N, C>::is_constant () const
+{
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      if (this->coeffs[i] != 0)
+       return false;
+  return true;
+}
+
+/* Return true if the polynomial value is a compile-time constant,
+   storing its value in CONST_VALUE if so.  */
+
+template<unsigned int N, typename C>
+template<typename T>
+inline typename if_lossless<T, C, bool>::type
+poly_int_pod<N, C>::is_constant (T *const_value) const
+{
+  if (is_constant ())
+    {
+      *const_value = this->coeffs[0];
+      return true;
+    }
+  return false;
+}
+
+/* Return the value of a polynomial that is already known to be a
+   compile-time constant.
+
+   NOTE: When using this function, please add a comment above the call
+   explaining why we know the value is constant in that context.  */
+
+template<unsigned int N, typename C>
+inline C
+poly_int_pod<N, C>::to_constant () const
+{
+  gcc_checking_assert (is_constant ());
+  return this->coeffs[0];
+}
+
+/* Convert X to a wide_int-based polynomial in which each coefficient
+   has BITSIZE bits.  If X's coefficients are smaller than BITSIZE,
+   extend them according to SGN.  */
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline poly_int<N, C>
+poly_int_pod<N, C>::from (const poly_int_pod<N, Ca> &a,
+                         unsigned int bitsize, signop sgn)
+{
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, C::from (a.coeffs[i], bitsize, sgn));
+  return r;
+}
+
+/* Convert X to a fixed_wide_int-based polynomial, extending according
+   to SGN.  */
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline poly_int<N, C>
+poly_int_pod<N, C>::from (const poly_int_pod<N, Ca> &a, signop sgn)
+{
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, C::from (a.coeffs[i], sgn));
+  return r;
+}
+
+/* Return true if the coefficients of this generic_wide_int-based
+   polynomial can be represented as signed HOST_WIDE_INTs without loss
+   of precision.  Store the HOST_WIDE_INT representation in *R if so.  */
+
+template<unsigned int N, typename C>
+inline bool
+poly_int_pod<N, C>::to_shwi (poly_int_pod<N, HOST_WIDE_INT> *r) const
+{
+  for (unsigned int i = 0; i < N; i++)
+    if (!wi::fits_shwi_p (this->coeffs[i]))
+      return false;
+  for (unsigned int i = 0; i < N; i++)
+    r->coeffs[i] = this->coeffs[i].to_shwi ();
+  return true;
+}
+
+/* Return true if the coefficients of this generic_wide_int-based
+   polynomial can be represented as unsigned HOST_WIDE_INTs without
+   loss of precision.  Store the unsigned HOST_WIDE_INT representation
+   in *R if so.  */
+
+template<unsigned int N, typename C>
+inline bool
+poly_int_pod<N, C>::to_uhwi (poly_int_pod<N, unsigned HOST_WIDE_INT> *r) const
+{
+  for (unsigned int i = 0; i < N; i++)
+    if (!wi::fits_uhwi_p (this->coeffs[i]))
+      return false;
+  for (unsigned int i = 0; i < N; i++)
+    r->coeffs[i] = this->coeffs[i].to_uhwi ();
+  return true;
+}
+
+/* Force a generic_wide_int-based constant to HOST_WIDE_INT precision,
+   truncating if necessary.  */
+
+template<unsigned int N, typename C>
+inline poly_int<N, HOST_WIDE_INT>
+poly_int_pod<N, C>::force_shwi () const
+{
+  poly_int_pod<N, HOST_WIDE_INT> r;
+  for (unsigned int i = 0; i < N; i++)
+    r.coeffs[i] = this->coeffs[i].to_shwi ();
+  return r;
+}
+
+/* Force a generic_wide_int-based constant to unsigned HOST_WIDE_INT precision,
+   truncating if necessary.  */
+
+template<unsigned int N, typename C>
+inline poly_int<N, unsigned HOST_WIDE_INT>
+poly_int_pod<N, C>::force_uhwi () const
+{
+  poly_int_pod<N, unsigned HOST_WIDE_INT> r;
+  for (unsigned int i = 0; i < N; i++)
+    r.coeffs[i] = this->coeffs[i].to_uhwi ();
+  return r;
+}
+
+#if POLY_INT_CONVERSION
+/* Provide a conversion operator to constants.  */
+
+template<unsigned int N, typename C>
+inline
+poly_int_pod<N, C>::operator C () const
+{
+  gcc_checking_assert (this->is_constant ());
+  return this->coeffs[0];
+}
+#endif
+
+/* The main class for polynomial integers.  The class provides
+   constructors that are necessarily missing from the POD base.  */
+template<unsigned int N, typename C>
+class poly_int : public poly_int_pod<N, C>
+{
+public:
+  poly_int () {}
+
+  template<typename Ca>
+  poly_int (const poly_int<N, Ca> &);
+  template<typename Ca>
+  poly_int (const poly_int_pod<N, Ca> &);
+  template<typename C0>
+  poly_int (const C0 &);
+  template<typename C0, typename C1>
+  poly_int (const C0 &, const C1 &);
+
+  template<typename Ca>
+  poly_int &operator = (const poly_int_pod<N, Ca> &);
+  template<typename Ca>
+  typename if_nonpoly<Ca, poly_int>::type &operator = (const Ca &);
+
+  template<typename Ca>
+  poly_int &operator += (const poly_int_pod<N, Ca> &);
+  template<typename Ca>
+  typename if_nonpoly<Ca, poly_int>::type &operator += (const Ca &);
+
+  template<typename Ca>
+  poly_int &operator -= (const poly_int_pod<N, Ca> &);
+  template<typename Ca>
+  typename if_nonpoly<Ca, poly_int>::type &operator -= (const Ca &);
+
+  template<typename Ca>
+  typename if_nonpoly<Ca, poly_int>::type &operator *= (const Ca &);
+
+  poly_int &operator <<= (unsigned int);
+};
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline
+poly_int<N, C>::poly_int (const poly_int<N, Ca> &a)
+{
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, *this, i, a.coeffs[i]);
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline
+poly_int<N, C>::poly_int (const poly_int_pod<N, Ca> &a)
+{
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, *this, i, a.coeffs[i]);
+}
+
+template<unsigned int N, typename C>
+template<typename C0>
+inline
+poly_int<N, C>::poly_int (const C0 &c0)
+{
+  POLY_SET_COEFF (C, *this, 0, c0);
+  for (unsigned int i = 1; i < N; i++)
+    POLY_SET_COEFF (C, *this, i, wi::ints_for<C>::zero (this->coeffs[0]));
+}
+
+template<unsigned int N, typename C>
+template<typename C0, typename C1>
+inline
+poly_int<N, C>::poly_int (const C0 &c0, const C1 &c1)
+{
+  STATIC_ASSERT (N >= 2);
+  POLY_SET_COEFF (C, *this, 0, c0);
+  POLY_SET_COEFF (C, *this, 1, c1);
+  for (unsigned int i = 2; i < N; i++)
+    POLY_SET_COEFF (C, *this, i, wi::ints_for<C>::zero (this->coeffs[0]));
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline poly_int<N, C>&
+poly_int<N, C>::operator = (const poly_int_pod<N, Ca> &a)
+{
+  for (unsigned int i = 0; i < N; i++)
+    this->coeffs[i] = a.coeffs[i];
+  return *this;
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline typename if_nonpoly<Ca, poly_int<N, C> >::type &
+poly_int<N, C>::operator = (const Ca &a)
+{
+  this->coeffs[0] = a;
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      this->coeffs[i] = wi::ints_for<C>::zero (this->coeffs[0]);
+  return *this;
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline poly_int<N, C>&
+poly_int<N, C>::operator += (const poly_int_pod<N, Ca> &a)
+{
+  for (unsigned int i = 0; i < N; i++)
+    this->coeffs[i] += a.coeffs[i];
+  return *this;
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline typename if_nonpoly<Ca, poly_int<N, C> >::type &
+poly_int<N, C>::operator += (const Ca &a)
+{
+  this->coeffs[0] += a;
+  return *this;
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline poly_int<N, C>&
+poly_int<N, C>::operator -= (const poly_int_pod<N, Ca> &a)
+{
+  for (unsigned int i = 0; i < N; i++)
+    this->coeffs[i] -= a.coeffs[i];
+  return *this;
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline typename if_nonpoly<Ca, poly_int<N, C> >::type &
+poly_int<N, C>::operator -= (const Ca &a)
+{
+  this->coeffs[0] -= a;
+  return *this;
+}
+
+template<unsigned int N, typename C>
+template<typename Ca>
+inline typename if_nonpoly<Ca, poly_int<N, C> >::type &
+poly_int<N, C>::operator *= (const Ca &a)
+{
+  for (unsigned int i = 0; i < N; i++)
+    this->coeffs[i] *= a;
+  return *this;
+}
+
+template<unsigned int N, typename C>
+inline poly_int<N, C>&
+poly_int<N, C>::operator <<= (unsigned int a)
+{
+  for (unsigned int i = 0; i < N; i++)
+    this->coeffs[i] <<= a;
+  return *this;
+}
+
+/* Return true if every coefficient of A is in the inclusive range [B, C].  */
+
+template<typename Ca, typename Cb, typename Cc>
+inline typename if_nonpoly<Ca, bool>::type
+coeffs_in_range_p (const Ca &a, const Cb &b, const Cc &c)
+{
+  return a >= b && a <= c;
+}
+
+template<unsigned int N, typename Ca, typename Cb, typename Cc>
+inline typename if_nonpoly<Ca, bool>::type
+coeffs_in_range_p (const poly_int_pod<N, Ca> &a, const Cb &b, const Cc &c)
+{
+  for (unsigned int i = 0; i < N; i++)
+    if (a.coeffs[i] < b || a.coeffs[i] > c)
+      return false;
+  return true;
+}
+
+namespace wi {
+/* Poly version of wi::shwi, with the same interface.  */
+
+template<unsigned int N>
+inline poly_int<N, hwi_with_prec>
+shwi (const poly_int_pod<N, HOST_WIDE_INT> &a, unsigned int precision)
+{
+  poly_int<N, hwi_with_prec> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (hwi_with_prec, r, i, wi::shwi (a.coeffs[i], precision));
+  return r;
+}
+
+/* Poly version of wi::uhwi, with the same interface.  */
+
+template<unsigned int N>
+inline poly_int<N, hwi_with_prec>
+uhwi (const poly_int_pod<N, unsigned HOST_WIDE_INT> &a, unsigned int precision)
+{
+  poly_int<N, hwi_with_prec> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (hwi_with_prec, r, i, wi::uhwi (a.coeffs[i], precision));
+  return r;
+}
+
+/* Poly version of wi::sext, with the same interface.  */
+
+template<unsigned int N, typename Ca>
+inline POLY_POLY_RESULT (N, Ca, Ca)
+sext (const poly_int_pod<N, Ca> &a, unsigned int precision)
+{
+  typedef POLY_POLY_COEFF (Ca, Ca) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, wi::sext (a.coeffs[i], precision));
+  return r;
+}
+
+/* Poly version of wi::zext, with the same interface.  */
+
+template<unsigned int N, typename Ca>
+inline POLY_POLY_RESULT (N, Ca, Ca)
+zext (const poly_int_pod<N, Ca> &a, unsigned int precision)
+{
+  typedef POLY_POLY_COEFF (Ca, Ca) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, wi::zext (a.coeffs[i], precision));
+  return r;
+}
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_POLY_RESULT (N, Ca, Cb)
+operator + (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_POLY_COEFF (Ca, Cb) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, NCa (a.coeffs[i]) + b.coeffs[i]);
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_CONST_RESULT (N, Ca, Cb)
+operator + (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CONST_COEFF (Ca, Cb) C;
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, NCa (a.coeffs[0]) + b);
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      POLY_SET_COEFF (C, r, i, NCa (a.coeffs[i]));
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline CONST_POLY_RESULT (N, Ca, Cb)
+operator + (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  typedef POLY_CAST (Cb, Ca) NCb;
+  typedef CONST_POLY_COEFF (Ca, Cb) C;
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, a + NCb (b.coeffs[0]));
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      POLY_SET_COEFF (C, r, i, NCb (b.coeffs[i]));
+  return r;
+}
+
+namespace wi {
+/* Poly versions of wi::add, with the same interface.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, WI_BINARY_RESULT (Ca, Cb)>
+add (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  typedef WI_BINARY_RESULT (Ca, Cb) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, wi::add (a.coeffs[i], b.coeffs[i]));
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, WI_BINARY_RESULT (Ca, Cb)>
+add (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  typedef WI_BINARY_RESULT (Ca, Cb) C;
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, wi::add (a.coeffs[0], b));
+  for (unsigned int i = 1; i < N; i++)
+    POLY_SET_COEFF (C, r, i, wi::add (a.coeffs[i],
+                                     wi::ints_for<Cb>::zero (b)));
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, WI_BINARY_RESULT (Ca, Cb)>
+add (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  typedef WI_BINARY_RESULT (Ca, Cb) C;
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, wi::add (a, b.coeffs[0]));
+  for (unsigned int i = 1; i < N; i++)
+    POLY_SET_COEFF (C, r, i, wi::add (wi::ints_for<Ca>::zero (a),
+                                     b.coeffs[i]));
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, WI_BINARY_RESULT (Ca, Cb)>
+add (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b,
+     signop sgn, bool *overflow)
+{
+  typedef WI_BINARY_RESULT (Ca, Cb) C;
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, wi::add (a.coeffs[0], b.coeffs[0], sgn, overflow));
+  for (unsigned int i = 1; i < N; i++)
+    {
+      bool suboverflow;
+      POLY_SET_COEFF (C, r, i, wi::add (a.coeffs[i], b.coeffs[i], sgn,
+                                       &suboverflow));
+      *overflow |= suboverflow;
+    }
+  return r;
+}
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_POLY_RESULT (N, Ca, Cb)
+operator - (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_POLY_COEFF (Ca, Cb) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, NCa (a.coeffs[i]) - b.coeffs[i]);
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_CONST_RESULT (N, Ca, Cb)
+operator - (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CONST_COEFF (Ca, Cb) C;
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, NCa (a.coeffs[0]) - b);
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      POLY_SET_COEFF (C, r, i, NCa (a.coeffs[i]));
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline CONST_POLY_RESULT (N, Ca, Cb)
+operator - (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  typedef POLY_CAST (Cb, Ca) NCb;
+  typedef CONST_POLY_COEFF (Ca, Cb) C;
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, a - NCb (b.coeffs[0]));
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      POLY_SET_COEFF (C, r, i, -NCb (b.coeffs[i]));
+  return r;
+}
+
+namespace wi {
+/* Poly versions of wi::sub, with the same interface.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, WI_BINARY_RESULT (Ca, Cb)>
+sub (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  typedef WI_BINARY_RESULT (Ca, Cb) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, wi::sub (a.coeffs[i], b.coeffs[i]));
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, WI_BINARY_RESULT (Ca, Cb)>
+sub (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  typedef WI_BINARY_RESULT (Ca, Cb) C;
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, wi::sub (a.coeffs[0], b));
+  for (unsigned int i = 1; i < N; i++)
+    POLY_SET_COEFF (C, r, i, wi::sub (a.coeffs[i],
+                                     wi::ints_for<Cb>::zero (b)));
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, WI_BINARY_RESULT (Ca, Cb)>
+sub (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  typedef WI_BINARY_RESULT (Ca, Cb) C;
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, wi::sub (a, b.coeffs[0]));
+  for (unsigned int i = 1; i < N; i++)
+    POLY_SET_COEFF (C, r, i, wi::sub (wi::ints_for<Ca>::zero (a),
+                                     b.coeffs[i]));
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, WI_BINARY_RESULT (Ca, Cb)>
+sub (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b,
+     signop sgn, bool *overflow)
+{
+  typedef WI_BINARY_RESULT (Ca, Cb) C;
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, wi::sub (a.coeffs[0], b.coeffs[0], sgn, overflow));
+  for (unsigned int i = 1; i < N; i++)
+    {
+      bool suboverflow;
+      POLY_SET_COEFF (C, r, i, wi::sub (a.coeffs[i], b.coeffs[i], sgn,
+                                       &suboverflow));
+      *overflow |= suboverflow;
+    }
+  return r;
+}
+}
+
+template<unsigned int N, typename Ca>
+inline POLY_POLY_RESULT (N, Ca, Ca)
+operator - (const poly_int_pod<N, Ca> &a)
+{
+  typedef POLY_CAST (Ca, Ca) NCa;
+  typedef POLY_POLY_COEFF (Ca, Ca) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, -NCa (a.coeffs[i]));
+  return r;
+}
+
+namespace wi {
+/* Poly version of wi::neg, with the same interface.  */
+
+template<unsigned int N, typename Ca>
+inline poly_int<N, WI_UNARY_RESULT (Ca)>
+neg (const poly_int_pod<N, Ca> &a)
+{
+  typedef WI_UNARY_RESULT (Ca) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, wi::neg (a.coeffs[i]));
+  return r;
+}
+
+template<unsigned int N, typename Ca>
+inline poly_int<N, WI_UNARY_RESULT (Ca)>
+neg (const poly_int_pod<N, Ca> &a, bool *overflow)
+{
+  typedef WI_UNARY_RESULT (Ca) C;
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, wi::neg (a.coeffs[0], overflow));
+  for (unsigned int i = 1; i < N; i++)
+    {
+      bool suboverflow;
+      POLY_SET_COEFF (C, r, i, wi::neg (a.coeffs[i], &suboverflow));
+      *overflow |= suboverflow;
+    }
+  return r;
+}
+}
+
+template<unsigned int N, typename Ca>
+inline POLY_POLY_RESULT (N, Ca, Ca)
+operator ~ (const poly_int_pod<N, Ca> &a)
+{
+  if (N >= 2)
+    return -1 - a;
+  return ~a.coeffs[0];
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_CONST_RESULT (N, Ca, Cb)
+operator * (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CONST_COEFF (Ca, Cb) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, NCa (a.coeffs[i]) * b);
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline CONST_POLY_RESULT (N, Ca, Cb)
+operator * (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef CONST_POLY_COEFF (Ca, Cb) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, NCa (a) * b.coeffs[i]);
+  return r;
+}
+
+namespace wi {
+/* Poly versions of wi::mul, with the same interface.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, WI_BINARY_RESULT (Ca, Cb)>
+mul (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  typedef WI_BINARY_RESULT (Ca, Cb) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, wi::mul (a.coeffs[i], b));
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, WI_BINARY_RESULT (Ca, Cb)>
+mul (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  typedef WI_BINARY_RESULT (Ca, Cb) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, wi::mul (a, b.coeffs[i]));
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, WI_BINARY_RESULT (Ca, Cb)>
+mul (const poly_int_pod<N, Ca> &a, const Cb &b,
+     signop sgn, bool *overflow)
+{
+  typedef WI_BINARY_RESULT (Ca, Cb) C;
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, wi::mul (a.coeffs[0], b, sgn, overflow));
+  for (unsigned int i = 1; i < N; i++)
+    {
+      bool suboverflow;
+      POLY_SET_COEFF (C, r, i, wi::mul (a.coeffs[i], b, sgn, &suboverflow));
+      *overflow |= suboverflow;
+    }
+  return r;
+}
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_POLY_RESULT (N, Ca, Ca)
+operator << (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  typedef POLY_CAST (Ca, Ca) NCa;
+  typedef POLY_POLY_COEFF (Ca, Ca) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, NCa (a.coeffs[i]) << b);
+  return r;
+}
+
+namespace wi {
+/* Poly version of wi::lshift, with the same interface.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, WI_BINARY_RESULT (Ca, Ca)>
+lshift (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  typedef WI_BINARY_RESULT (Ca, Ca) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, wi::lshift (a.coeffs[i], b));
+  return r;
+}
+}
+
+/* Return true if a0 + a1 * x might equal b0 + b1 * x for some nonnegative
+   integer x.  */
+
+template<typename Ca, typename Cb>
+inline bool
+maybe_eq_2 (const Ca &a0, const Ca &a1, const Cb &b0, const Cb &b1)
+{
+  if (a1 != b1)
+     /*      a0 + a1 * x == b0 + b1 * x
+       ==> (a1 - b1) * x == b0 - a0
+       ==>             x == (b0 - a0) / (a1 - b1)
+
+       We need to test whether that's a valid value of x.
+       (b0 - a0) and (a1 - b1) must not have opposite signs
+       and the result must be integral.  */
+    return (a1 < b1
+           ? b0 <= a0 && (a0 - b0) % (b1 - a1) == 0
+           : b0 >= a0 && (b0 - a0) % (a1 - b1) == 0);
+  return a0 == b0;
+}
+
+/* Return true if a0 + a1 * x might equal b for some nonnegative
+   integer x.  */
+
+template<typename Ca, typename Cb>
+inline bool
+maybe_eq_2 (const Ca &a0, const Ca &a1, const Cb &b)
+{
+  if (a1 != 0)
+     /*      a0 + a1 * x == b
+       ==>             x == (b - a0) / a1
+
+       We need to test whether that's a valid value of x.
+       (b - a0) and a1 must not have opposite signs and the
+       result must be integral.  */
+    return (a1 < 0
+           ? b <= a0 && (a0 - b) % a1 == 0
+           : b >= a0 && (b - a0) % a1 == 0);
+  return a0 == b;
+}
+
+/* Return true if A might equal B for some indeterminate values.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline bool
+maybe_eq (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  STATIC_ASSERT (N <= 2);
+  if (N == 2)
+    return maybe_eq_2 (a.coeffs[0], a.coeffs[1], b.coeffs[0], b.coeffs[1]);
+  return a.coeffs[0] == b.coeffs[0];
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline typename if_nonpoly<Cb, bool>::type
+maybe_eq (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  STATIC_ASSERT (N <= 2);
+  if (N == 2)
+    return maybe_eq_2 (a.coeffs[0], a.coeffs[1], b);
+  return a.coeffs[0] == b;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline typename if_nonpoly<Ca, bool>::type
+maybe_eq (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  STATIC_ASSERT (N <= 2);
+  if (N == 2)
+    return maybe_eq_2 (b.coeffs[0], b.coeffs[1], a);
+  return a == b.coeffs[0];
+}
+
+template<typename Ca, typename Cb>
+inline typename if_nonpoly2<Ca, Cb, bool>::type
+maybe_eq (const Ca &a, const Cb &b)
+{
+  return a == b;
+}
+
+/* Return true if A might not equal B for some indeterminate values.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline bool
+maybe_ne (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      if (a.coeffs[i] != b.coeffs[i])
+       return true;
+  return a.coeffs[0] != b.coeffs[0];
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline typename if_nonpoly<Cb, bool>::type
+maybe_ne (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      if (a.coeffs[i] != 0)
+       return true;
+  return a.coeffs[0] != b;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline typename if_nonpoly<Ca, bool>::type
+maybe_ne (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      if (0 != b.coeffs[i])
+       return true;
+  return a != b.coeffs[0];
+}
+
+template<typename Ca, typename Cb>
+inline typename if_nonpoly2<Ca, Cb, bool>::type
+maybe_ne (const Ca &a, const Cb &b)
+{
+  return a != b;
+}
+
+/* Return true if A is known to be equal to B.  */
+#define known_eq(A, B) (!maybe_ne (A, B))
+
+/* Return true if A is known to be unequal to B.  */
+#define known_ne(A, B) (!maybe_eq (A, B))
+
+/* Return true if A might be less than or equal to B for some
+   indeterminate values.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline bool
+maybe_le (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      if (a.coeffs[i] < b.coeffs[i])
+       return true;
+  return a.coeffs[0] <= b.coeffs[0];
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline typename if_nonpoly<Cb, bool>::type
+maybe_le (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      if (a.coeffs[i] < 0)
+       return true;
+  return a.coeffs[0] <= b;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline typename if_nonpoly<Ca, bool>::type
+maybe_le (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      if (0 < b.coeffs[i])
+       return true;
+  return a <= b.coeffs[0];
+}
+
+template<typename Ca, typename Cb>
+inline typename if_nonpoly2<Ca, Cb, bool>::type
+maybe_le (const Ca &a, const Cb &b)
+{
+  return a <= b;
+}
+
+/* Return true if A might be less than B for some indeterminate values.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline bool
+maybe_lt (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      if (a.coeffs[i] < b.coeffs[i])
+       return true;
+  return a.coeffs[0] < b.coeffs[0];
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline typename if_nonpoly<Cb, bool>::type
+maybe_lt (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      if (a.coeffs[i] < 0)
+       return true;
+  return a.coeffs[0] < b;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline typename if_nonpoly<Ca, bool>::type
+maybe_lt (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      if (0 < b.coeffs[i])
+       return true;
+  return a < b.coeffs[0];
+}
+
+template<typename Ca, typename Cb>
+inline typename if_nonpoly2<Ca, Cb, bool>::type
+maybe_lt (const Ca &a, const Cb &b)
+{
+  return a < b;
+}
+
+/* Return true if A may be greater than or equal to B.  */
+#define maybe_ge(A, B) maybe_le (B, A)
+
+/* Return true if A may be greater than B.  */
+#define maybe_gt(A, B) maybe_lt (B, A)
+
+/* Return true if A is known to be less than or equal to B.  */
+#define known_le(A, B) (!maybe_gt (A, B))
+
+/* Return true if A is known to be less than B.  */
+#define known_lt(A, B) (!maybe_ge (A, B))
+
+/* Return true if A is known to be greater than B.  */
+#define known_gt(A, B) (!maybe_le (A, B))
+
+/* Return true if A is known to be greater than or equal to B.  */
+#define known_ge(A, B) (!maybe_lt (A, B))
+
+/* Return true if A and B are ordered by the partial ordering known_le.  */
+
+template<typename T1, typename T2>
+inline bool
+ordered_p (const T1 &a, const T2 &b)
+{
+  return ((poly_int_traits<T1>::num_coeffs == 1
+          && poly_int_traits<T2>::num_coeffs == 1)
+         || known_le (a, b)
+         || known_le (b, a));
+}
+
+/* Assert that A and B are known to be ordered and return the minimum
+   of the two.
+
+   NOTE: When using this function, please add a comment above the call
+   explaining why we know the values are ordered in that context.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_POLY_RESULT (N, Ca, Cb)
+ordered_min (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  if (known_le (a, b))
+    return a;
+  else
+    {
+      if (N > 1)
+       gcc_checking_assert (known_le (b, a));
+      return b;
+    }
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline CONST_POLY_RESULT (N, Ca, Cb)
+ordered_min (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  if (known_le (a, b))
+    return a;
+  else
+    {
+      if (N > 1)
+       gcc_checking_assert (known_le (b, a));
+      return b;
+    }
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_CONST_RESULT (N, Ca, Cb)
+ordered_min (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  if (known_le (a, b))
+    return a;
+  else
+    {
+      if (N > 1)
+       gcc_checking_assert (known_le (b, a));
+      return b;
+    }
+}
+
+/* Assert that A and B are known to be ordered and return the maximum
+   of the two.
+
+   NOTE: When using this function, please add a comment above the call
+   explaining why we know the values are ordered in that context.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_POLY_RESULT (N, Ca, Cb)
+ordered_max (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  if (known_le (a, b))
+    return b;
+  else
+    {
+      if (N > 1)
+       gcc_checking_assert (known_le (b, a));
+      return a;
+    }
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline CONST_POLY_RESULT (N, Ca, Cb)
+ordered_max (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  if (known_le (a, b))
+    return b;
+  else
+    {
+      if (N > 1)
+       gcc_checking_assert (known_le (b, a));
+      return a;
+    }
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_CONST_RESULT (N, Ca, Cb)
+ordered_max (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  if (known_le (a, b))
+    return b;
+  else
+    {
+      if (N > 1)
+       gcc_checking_assert (known_le (b, a));
+      return a;
+    }
+}
+
+/* Return a constant lower bound on the value of A, which is known
+   to be nonnegative.  */
+
+template<unsigned int N, typename Ca>
+inline Ca
+constant_lower_bound (const poly_int_pod<N, Ca> &a)
+{
+  gcc_checking_assert (known_ge (a, POLY_INT_TYPE (Ca) (0)));
+  return a.coeffs[0];
+}
+
+/* Return a value that is known to be no greater than A and B.  This
+   will be the greatest lower bound for some indeterminate values but
+   not necessarily for all.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_CONST_RESULT (N, Ca, Cb)
+lower_bound (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CAST (Cb, Ca) NCb;
+  typedef POLY_INT_TYPE (Cb) ICb;
+  typedef POLY_CONST_COEFF (Ca, Cb) C;
+
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, MIN (NCa (a.coeffs[0]), NCb (b)));
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      POLY_SET_COEFF (C, r, i, MIN (NCa (a.coeffs[i]), ICb (0)));
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline CONST_POLY_RESULT (N, Ca, Cb)
+lower_bound (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  return lower_bound (b, a);
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_POLY_RESULT (N, Ca, Cb)
+lower_bound (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CAST (Cb, Ca) NCb;
+  typedef POLY_POLY_COEFF (Ca, Cb) C;
+
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, MIN (NCa (a.coeffs[i]), NCb (b.coeffs[i])));
+  return r;
+}
+
+template<typename Ca, typename Cb>
+inline CONST_CONST_RESULT (N, Ca, Cb)
+lower_bound (const Ca &a, const Cb &b)
+{
+  return a < b ? a : b;
+}
+
+/* Return a value that is known to be no less than A and B.  This will
+   be the least upper bound for some indeterminate values but not
+   necessarily for all.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_CONST_RESULT (N, Ca, Cb)
+upper_bound (const poly_int_pod<N, Ca> &a, const Cb &b)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CAST (Cb, Ca) NCb;
+  typedef POLY_INT_TYPE (Cb) ICb;
+  typedef POLY_CONST_COEFF (Ca, Cb) C;
+
+  poly_int<N, C> r;
+  POLY_SET_COEFF (C, r, 0, MAX (NCa (a.coeffs[0]), NCb (b)));
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      POLY_SET_COEFF (C, r, i, MAX (NCa (a.coeffs[i]), ICb (0)));
+  return r;
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline CONST_POLY_RESULT (N, Ca, Cb)
+upper_bound (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  return upper_bound (b, a);
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_POLY_RESULT (N, Ca, Cb)
+upper_bound (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CAST (Cb, Ca) NCb;
+  typedef POLY_POLY_COEFF (Ca, Cb) C;
+
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (C, r, i, MAX (NCa (a.coeffs[i]), NCb (b.coeffs[i])));
+  return r;
+}
+
+/* Return the greatest common divisor of all nonzero coefficients, or zero
+   if all coefficients are zero.  */
+
+template<unsigned int N, typename Ca>
+inline POLY_BINARY_COEFF (Ca, Ca)
+coeff_gcd (const poly_int_pod<N, Ca> &a)
+{
+  /* Find the first nonzero coefficient, stopping at 0 whatever happens.  */
+  unsigned int i;
+  for (i = N - 1; i > 0; --i)
+    if (a.coeffs[i] != 0)
+      break;
+  typedef POLY_BINARY_COEFF (Ca, Ca) C;
+  C r = a.coeffs[i];
+  for (unsigned int j = 0; j < i; ++j)
+    if (a.coeffs[j] != 0)
+      r = gcd (r, C (a.coeffs[j]));
+  return r;
+}
+
+/* Return a value that is a multiple of both A and B.  This will be the
+   least common multiple for some indeterminate values but necessarily
+   for all.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+POLY_CONST_RESULT (N, Ca, Cb)
+common_multiple (const poly_int_pod<N, Ca> &a, Cb b)
+{
+  POLY_BINARY_COEFF (Ca, Ca) xgcd = coeff_gcd (a);
+  return a * (least_common_multiple (xgcd, b) / xgcd);
+}
+
+template<unsigned int N, typename Ca, typename Cb>
+inline CONST_POLY_RESULT (N, Ca, Cb)
+common_multiple (const Ca &a, const poly_int_pod<N, Cb> &b)
+{
+  return common_multiple (b, a);
+}
+
+/* Return a value that is a multiple of both A and B, asserting that
+   such a value exists.  The result will be the least common multiple
+   for some indeterminate values but necessarily for all.
+
+   NOTE: When using this function, please add a comment above the call
+   explaining why we know the values have a common multiple (which might
+   for example be because we know A / B is rational).  */
+
+template<unsigned int N, typename Ca, typename Cb>
+POLY_POLY_RESULT (N, Ca, Cb)
+force_common_multiple (const poly_int_pod<N, Ca> &a,
+                      const poly_int_pod<N, Cb> &b)
+{
+  if (b.is_constant ())
+    return common_multiple (a, b.coeffs[0]);
+  if (a.is_constant ())
+    return common_multiple (a.coeffs[0], b);
+
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CAST (Cb, Ca) NCb;
+  typedef POLY_BINARY_COEFF (Ca, Cb) C;
+  typedef POLY_INT_TYPE (Ca) ICa;
+
+  for (unsigned int i = 1; i < N; ++i)
+    if (a.coeffs[i] != ICa (0))
+      {
+       C lcm = least_common_multiple (NCa (a.coeffs[i]), NCb (b.coeffs[i]));
+       C amul = lcm / a.coeffs[i];
+       C bmul = lcm / b.coeffs[i];
+       for (unsigned int j = 0; j < N; ++j)
+         gcc_checking_assert (a.coeffs[j] * amul == b.coeffs[j] * bmul);
+       return a * amul;
+      }
+  gcc_unreachable ();
+}
+
+/* Compare A and B for sorting purposes, returning -1 if A should come
+   before B, 0 if A and B are identical, and 1 if A should come after B.
+   This is a lexicographical compare of the coefficients in reverse order.
+
+   A consequence of this is that all constant sizes come before all
+   non-constant ones, regardless of magnitude (since a size is never
+   negative).  This is what most callers want.  For example, when laying
+   data out on the stack, it's better to keep all the constant-sized
+   data together so that it can be accessed as a constant offset from a
+   single base.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline int
+compare_sizes_for_sort (const poly_int_pod<N, Ca> &a,
+                       const poly_int_pod<N, Cb> &b)
+{
+  for (unsigned int i = N; i-- > 0; )
+    if (a.coeffs[i] != b.coeffs[i])
+      return a.coeffs[i] < b.coeffs[i] ? -1 : 1;
+  return 0;
+}
+
+/* Return true if we can calculate VALUE & (ALIGN - 1) at compile time.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline bool
+can_align_p (const poly_int_pod<N, Ca> &value, Cb align)
+{
+  for (unsigned int i = 1; i < N; i++)
+    if ((value.coeffs[i] & (align - 1)) != 0)
+      return false;
+  return true;
+}
+
+/* Return true if we can align VALUE up to the smallest multiple of
+   ALIGN that is >= VALUE.  Store the aligned value in *ALIGNED if so.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline bool
+can_align_up (const poly_int_pod<N, Ca> &value, Cb align,
+             poly_int_pod<N, Ca> *aligned)
+{
+  if (!can_align_p (value, align))
+    return false;
+  *aligned = value + (-value.coeffs[0] & (align - 1));
+  return true;
+}
+
+/* Return true if we can align VALUE down to the largest multiple of
+   ALIGN that is <= VALUE.  Store the aligned value in *ALIGNED if so.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline bool
+can_align_down (const poly_int_pod<N, Ca> &value, Cb align,
+               poly_int_pod<N, Ca> *aligned)
+{
+  if (!can_align_p (value, align))
+    return false;
+  *aligned = value - (value.coeffs[0] & (align - 1));
+  return true;
+}
+
+/* Return true if we can align A and B up to the smallest multiples of
+   ALIGN that are >= A and B respectively, and if doing so gives the
+   same value.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cc>
+inline bool
+known_equal_after_align_up (const poly_int_pod<N, Ca> &a,
+                           const poly_int_pod<N, Cb> &b,
+                           Cc align)
+{
+  poly_int<N, Ca> aligned_a;
+  poly_int<N, Cb> aligned_b;
+  return (can_align_up (a, align, &aligned_a)
+         && can_align_up (b, align, &aligned_b)
+         && known_eq (aligned_a, aligned_b));
+}
+
+/* Return true if we can align A and B down to the largest multiples of
+   ALIGN that are <= A and B respectively, and if doing so gives the
+   same value.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cc>
+inline bool
+known_equal_after_align_down (const poly_int_pod<N, Ca> &a,
+                             const poly_int_pod<N, Cb> &b,
+                             Cc align)
+{
+  poly_int<N, Ca> aligned_a;
+  poly_int<N, Cb> aligned_b;
+  return (can_align_down (a, align, &aligned_a)
+         && can_align_down (b, align, &aligned_b)
+         && known_eq (aligned_a, aligned_b));
+}
+
+/* Assert that we can align VALUE to ALIGN at compile time and return
+   the smallest multiple of ALIGN that is >= VALUE.
+
+   NOTE: When using this function, please add a comment above the call
+   explaining why we know the non-constant coefficients must already
+   be a multiple of ALIGN.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, Ca>
+force_align_up (const poly_int_pod<N, Ca> &value, Cb align)
+{
+  gcc_checking_assert (can_align_p (value, align));
+  return value + (-value.coeffs[0] & (align - 1));
+}
+
+/* Assert that we can align VALUE to ALIGN at compile time and return
+   the largest multiple of ALIGN that is <= VALUE.
+
+   NOTE: When using this function, please add a comment above the call
+   explaining why we know the non-constant coefficients must already
+   be a multiple of ALIGN.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, Ca>
+force_align_down (const poly_int_pod<N, Ca> &value, Cb align)
+{
+  gcc_checking_assert (can_align_p (value, align));
+  return value - (value.coeffs[0] & (align - 1));
+}
+
+/* Return a value <= VALUE that is a multiple of ALIGN.  It will be the
+   greatest such value for some indeterminate values but not necessarily
+   for all.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, Ca>
+aligned_lower_bound (const poly_int_pod<N, Ca> &value, Cb align)
+{
+  poly_int<N, Ca> r;
+  for (unsigned int i = 0; i < N; i++)
+    /* This form copes correctly with more type combinations than
+       value.coeffs[i] & -align would.  */
+    POLY_SET_COEFF (Ca, r, i, (value.coeffs[i]
+                              - (value.coeffs[i] & (align - 1))));
+  return r;
+}
+
+/* Return a value >= VALUE that is a multiple of ALIGN.  It will be the
+   least such value for some indeterminate values but not necessarily
+   for all.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, Ca>
+aligned_upper_bound (const poly_int_pod<N, Ca> &value, Cb align)
+{
+  poly_int<N, Ca> r;
+  for (unsigned int i = 0; i < N; i++)
+    POLY_SET_COEFF (Ca, r, i, (value.coeffs[i]
+                              + (-value.coeffs[i] & (align - 1))));
+  return r;
+}
+
+/* Assert that we can align VALUE to ALIGN at compile time.  Align VALUE
+   down to the largest multiple of ALIGN that is <= VALUE, then divide by
+   ALIGN.
+
+   NOTE: When using this function, please add a comment above the call
+   explaining why we know the non-constant coefficients must already
+   be a multiple of ALIGN.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, Ca>
+force_align_down_and_div (const poly_int_pod<N, Ca> &value, Cb align)
+{
+  gcc_checking_assert (can_align_p (value, align));
+
+  poly_int<N, Ca> r;
+  POLY_SET_COEFF (Ca, r, 0, ((value.coeffs[0]
+                             - (value.coeffs[0] & (align - 1)))
+                            / align));
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      POLY_SET_COEFF (Ca, r, i, value.coeffs[i] / align);
+  return r;
+}
+
+/* Assert that we can align VALUE to ALIGN at compile time.  Align VALUE
+   up to the smallest multiple of ALIGN that is >= VALUE, then divide by
+   ALIGN.
+
+   NOTE: When using this function, please add a comment above the call
+   explaining why we know the non-constant coefficients must already
+   be a multiple of ALIGN.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline poly_int<N, Ca>
+force_align_up_and_div (const poly_int_pod<N, Ca> &value, Cb align)
+{
+  gcc_checking_assert (can_align_p (value, align));
+
+  poly_int<N, Ca> r;
+  POLY_SET_COEFF (Ca, r, 0, ((value.coeffs[0]
+                             + (-value.coeffs[0] & (align - 1)))
+                            / align));
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      POLY_SET_COEFF (Ca, r, i, value.coeffs[i] / align);
+  return r;
+}
+
+/* Return true if we know at compile time the difference between VALUE
+   and the equal or preceding multiple of ALIGN.  Store the value in
+   *MISALIGN if so.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cm>
+inline bool
+known_misalignment (const poly_int_pod<N, Ca> &value, Cb align, Cm *misalign)
+{
+  gcc_checking_assert (align != 0);
+  if (!can_align_p (value, align))
+    return false;
+  *misalign = value.coeffs[0] & (align - 1);
+  return true;
+}
+
+/* Return X & (Y - 1), asserting that this value is known.  Please add
+   an a comment above callers to this function to explain why the condition
+   is known to hold.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_BINARY_COEFF (Ca, Ca)
+force_get_misalignment (const poly_int_pod<N, Ca> &a, Cb align)
+{
+  gcc_checking_assert (can_align_p (a, align));
+  return a.coeffs[0] & (align - 1);
+}
+
+/* Return the maximum alignment that A is known to have.  Return 0
+   if A is known to be zero.  */
+
+template<unsigned int N, typename Ca>
+inline POLY_BINARY_COEFF (Ca, Ca)
+known_alignment (const poly_int_pod<N, Ca> &a)
+{
+  typedef POLY_BINARY_COEFF (Ca, Ca) C;
+  C r = a.coeffs[0];
+  for (unsigned int i = 1; i < N; ++i)
+    r |= a.coeffs[i];
+  return r & -r;
+}
+
+/* Return true if we can compute A | B at compile time, storing the
+   result in RES if so.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cr>
+inline typename if_nonpoly<Cb, bool>::type
+can_ior_p (const poly_int_pod<N, Ca> &a, Cb b, Cr *result)
+{
+  /* Coefficients 1 and above must be a multiple of something greater
+     than B.  */
+  typedef POLY_INT_TYPE (Ca) int_type;
+  if (N >= 2)
+    for (unsigned int i = 1; i < N; i++)
+      if ((-(a.coeffs[i] & -a.coeffs[i]) & b) != int_type (0))
+       return false;
+  *result = a;
+  result->coeffs[0] |= b;
+  return true;
+}
+
+/* Return true if A is a constant multiple of B, storing the
+   multiple in *MULTIPLE if so.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cm>
+inline typename if_nonpoly<Cb, bool>::type
+constant_multiple_p (const poly_int_pod<N, Ca> &a, Cb b, Cm *multiple)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CAST (Cb, Ca) NCb;
+
+  /* Do the modulus before the constant check, to catch divide by
+     zero errors.  */
+  if (NCa (a.coeffs[0]) % NCb (b) != 0 || !a.is_constant ())
+    return false;
+  *multiple = NCa (a.coeffs[0]) / NCb (b);
+  return true;
+}
+
+template<unsigned int N, typename Ca, typename Cb, typename Cm>
+inline typename if_nonpoly<Ca, bool>::type
+constant_multiple_p (Ca a, const poly_int_pod<N, Cb> &b, Cm *multiple)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CAST (Cb, Ca) NCb;
+  typedef POLY_INT_TYPE (Ca) int_type;
+
+  /* Do the modulus before the constant check, to catch divide by
+     zero errors.  */
+  if (NCa (a) % NCb (b.coeffs[0]) != 0
+      || (a != int_type (0) && !b.is_constant ()))
+    return false;
+  *multiple = NCa (a) / NCb (b.coeffs[0]);
+  return true;
+}
+
+template<unsigned int N, typename Ca, typename Cb, typename Cm>
+inline bool
+constant_multiple_p (const poly_int_pod<N, Ca> &a,
+                    const poly_int_pod<N, Cb> &b, Cm *multiple)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CAST (Cb, Ca) NCb;
+  typedef POLY_INT_TYPE (Ca) ICa;
+  typedef POLY_INT_TYPE (Cb) ICb;
+  typedef POLY_BINARY_COEFF (Ca, Cb) C;
+
+  if (NCa (a.coeffs[0]) % NCb (b.coeffs[0]) != 0)
+    return false;
+
+  C r = NCa (a.coeffs[0]) / NCb (b.coeffs[0]);
+  for (unsigned int i = 1; i < N; ++i)
+    if (b.coeffs[i] == ICb (0)
+       ? a.coeffs[i] != ICa (0)
+       : (NCa (a.coeffs[i]) % NCb (b.coeffs[i]) != 0
+          || NCa (a.coeffs[i]) / NCb (b.coeffs[i]) != r))
+      return false;
+
+  *multiple = r;
+  return true;
+}
+
+/* Return true if A is a multiple of B.  */
+
+template<typename Ca, typename Cb>
+inline typename if_nonpoly2<Ca, Cb, bool>::type
+multiple_p (Ca a, Cb b)
+{
+  return a % b != 0;
+}
+
+/* Return true if A is a (polynomial) multiple of B.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline typename if_nonpoly<Cb, bool>::type
+multiple_p (const poly_int_pod<N, Ca> &a, Cb b)
+{
+  for (unsigned int i = 0; i < N; ++i)
+    if (a.coeffs[i] % b != 0)
+      return false;
+  return true;
+}
+
+/* Return true if A is a (constant) multiple of B.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline typename if_nonpoly<Ca, bool>::type
+multiple_p (Ca a, const poly_int_pod<N, Cb> &b)
+{
+  typedef POLY_INT_TYPE (Ca) int_type;
+
+  /* Do the modulus before the constant check, to catch divide by
+     potential zeros.  */
+  return a % b.coeffs[0] == 0 && (a == int_type (0) || b.is_constant ());
+}
+
+/* Return true if A is a (polynomial) multiple of B.  This handles cases
+   where either B is constant or the multiple is constant.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline bool
+multiple_p (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  if (b.is_constant ())
+    return multiple_p (a, b.coeffs[0]);
+  POLY_BINARY_COEFF (Ca, Ca) tmp;
+  return constant_multiple_p (a, b, &tmp);
+}
+
+/* Return true if A is a (constant) multiple of B, storing the
+   multiple in *MULTIPLE if so.  */
+
+template<typename Ca, typename Cb, typename Cm>
+inline typename if_nonpoly2<Ca, Cb, bool>::type
+multiple_p (Ca a, Cb b, Cm *multiple)
+{
+  if (a % b != 0)
+    return false;
+  *multiple = a / b;
+  return true;
+}
+
+/* Return true if A is a (polynomial) multiple of B, storing the
+   multiple in *MULTIPLE if so.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cm>
+inline typename if_nonpoly<Cb, bool>::type
+multiple_p (const poly_int_pod<N, Ca> &a, Cb b, poly_int_pod<N, Cm> *multiple)
+{
+  if (!multiple_p (a, b))
+    return false;
+  for (unsigned int i = 0; i < N; ++i)
+    multiple->coeffs[i] = a.coeffs[i] / b;
+  return true;
+}
+
+/* Return true if B is a constant and A is a (constant) multiple of B,
+   storing the multiple in *MULTIPLE if so.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cm>
+inline typename if_nonpoly<Ca, bool>::type
+multiple_p (Ca a, const poly_int_pod<N, Cb> &b, Cm *multiple)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+
+  /* Do the modulus before the constant check, to catch divide by
+     potential zeros.  */
+  if (a % b.coeffs[0] != 0 || (NCa (a) != 0 && !b.is_constant ()))
+    return false;
+  *multiple = a / b.coeffs[0];
+  return true;
+}
+
+/* Return true if A is a (polynomial) multiple of B, storing the
+   multiple in *MULTIPLE if so.  This handles cases where either
+   B is constant or the multiple is constant.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cm>
+inline bool
+multiple_p (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b,
+           poly_int_pod<N, Cm> *multiple)
+{
+  if (b.is_constant ())
+    return multiple_p (a, b.coeffs[0], multiple);
+  return constant_multiple_p (a, b, multiple);
+}
+
+/* Return A / B, given that A is known to be a multiple of B.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_CONST_RESULT (N, Ca, Cb)
+exact_div (const poly_int_pod<N, Ca> &a, Cb b)
+{
+  typedef POLY_CONST_COEFF (Ca, Cb) C;
+  poly_int<N, C> r;
+  for (unsigned int i = 0; i < N; i++)
+    {
+      gcc_checking_assert (a.coeffs[i] % b == 0);
+      POLY_SET_COEFF (C, r, i, a.coeffs[i] / b);
+    }
+  return r;
+}
+
+/* Return A / B, given that A is known to be a multiple of B.  */
+
+template<unsigned int N, typename Ca, typename Cb>
+inline POLY_POLY_RESULT (N, Ca, Cb)
+exact_div (const poly_int_pod<N, Ca> &a, const poly_int_pod<N, Cb> &b)
+{
+  if (b.is_constant ())
+    return exact_div (a, b.coeffs[0]);
+
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CAST (Cb, Ca) NCb;
+  typedef POLY_BINARY_COEFF (Ca, Cb) C;
+  typedef POLY_INT_TYPE (Cb) int_type;
+
+  gcc_checking_assert (a.coeffs[0] % b.coeffs[0] == 0);
+  C r = NCa (a.coeffs[0]) / NCb (b.coeffs[0]);
+  for (unsigned int i = 1; i < N; ++i)
+    gcc_checking_assert (b.coeffs[i] == int_type (0)
+                        ? a.coeffs[i] == int_type (0)
+                        : (a.coeffs[i] % b.coeffs[i] == 0
+                           && NCa (a.coeffs[i]) / NCb (b.coeffs[i]) == r));
+
+  return r;
+}
+
+/* Return true if there is some constant Q and polynomial r such that:
+
+     (1) a = b * Q + r
+     (2) |b * Q| <= |a|
+     (3) |r| < |b|
+
+   Store the value Q in *QUOTIENT if so.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cq>
+inline typename if_nonpoly2<Cb, Cq, bool>::type
+can_div_trunc_p (const poly_int_pod<N, Ca> &a, Cb b, Cq *quotient)
+{
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CAST (Cb, Ca) NCb;
+
+  /* Do the division before the constant check, to catch divide by
+     zero errors.  */
+  Cq q = NCa (a.coeffs[0]) / NCb (b);
+  if (!a.is_constant ())
+    return false;
+  *quotient = q;
+  return true;
+}
+
+template<unsigned int N, typename Ca, typename Cb, typename Cq>
+inline typename if_nonpoly<Cq, bool>::type
+can_div_trunc_p (const poly_int_pod<N, Ca> &a,
+                const poly_int_pod<N, Cb> &b,
+                Cq *quotient)
+{
+  /* We can calculate Q from the case in which the indeterminates
+     are zero.  */
+  typedef POLY_CAST (Ca, Cb) NCa;
+  typedef POLY_CAST (Cb, Ca) NCb;
+  typedef POLY_INT_TYPE (Ca) ICa;
+  typedef POLY_INT_TYPE (Cb) ICb;
+  typedef POLY_BINARY_COEFF (Ca, Cb) C;
+  C q = NCa (a.coeffs[0]) / NCb (b.coeffs[0]);
+
+  /* Check the other coefficients and record whether the division is exact.
+     The only difficult case is when it isn't.  If we require a and b to
+     ordered wrt zero, there can be no two coefficients of the same value
+     that have opposite signs.  This means that:
+
+        |a| = |a0| + |a1 * x1| + |a2 * x2| + ...
+        |b| = |b0| + |b1 * x1| + |b2 * x2| + ...
+
+      The Q we've just calculated guarantees:
+
+        |b0 * Q| <= |a0|
+        |a0 - b0 * Q| < |b0|
+
+      and so:
+
+        (2) |b * Q| <= |a|
+
+      is satisfied if:
+
+        |bi * xi * Q| <= |ai * xi|
+
+      for each i in [1, N].  This is trivially true when xi is zero.
+      When it isn't we need:
+
+        (2') |bi * Q| <= |ai|
+
+      r is calculated as:
+
+        r = r0 + r1 * x1 + r2 * x2 + ...
+        where ri = ai - bi * Q
+
+      Restricting to ordered a and b also guarantees that no two ris
+      have opposite signs, so we have:
+
+        |r| = |r0| + |r1 * x1| + |r2 * x2| + ...
+
+      We know from the calculation of Q that |r0| < |b0|, so:
+
+        (3) |r| < |b|
+
+      is satisfied if:
+
+        (3') |ai - bi * Q| <= |bi|
+
+      for each i in [1, N].  */
+  bool rem_p = NCa (a.coeffs[0]) % NCb (b.coeffs[0]) != 0;
+  for (unsigned int i = 1; i < N; ++i)
+    {
+      if (b.coeffs[i] == ICb (0))
+       {
+         /* For bi == 0 we simply need: (3') |ai| == 0.  */
+         if (a.coeffs[i] != ICa (0))
+           return false;
+       }
+      else
+       {
+         if (q == 0)
+           {
+             /* For Q == 0 we simply need: (3') |ai| <= |bi|.  */
+             if (a.coeffs[i] != ICa (0))
+               {
+                 /* Use negative absolute to avoid overflow, i.e.
+                    -|ai| >= -|bi|.  */
+                 C neg_abs_a = (a.coeffs[i] < 0 ? a.coeffs[i] : -a.coeffs[i]);
+                 C neg_abs_b = (b.coeffs[i] < 0 ? b.coeffs[i] : -b.coeffs[i]);
+                 if (neg_abs_a < neg_abs_b)
+                   return false;
+                 rem_p = true;
+               }
+           }
+         else
+           {
+             /* Otherwise just check for the case in which ai / bi == Q.  */
+             if (NCa (a.coeffs[i]) / NCb (b.coeffs[i]) != q)
+               return false;
+             if (NCa (a.coeffs[i]) % NCb (b.coeffs[i]) != 0)
+               rem_p = true;
+           }
+       }
+    }
+
+  /* If the division isn't exact, require both values to be ordered wrt 0,
+     so that we can guarantee conditions (2) and (3) for all indeterminate
+     values.  */
+  if (rem_p && (!ordered_p (a, ICa (0)) || !ordered_p (b, ICb (0))))
+    return false;
+
+  *quotient = q;
+  return true;
+}
+
+/* Likewise, but also store r in *REMAINDER.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cq, typename Cr>
+inline typename if_nonpoly<Cq, bool>::type
+can_div_trunc_p (const poly_int_pod<N, Ca> &a,
+                const poly_int_pod<N, Cb> &b,
+                Cq *quotient, Cr *remainder)
+{
+  if (!can_div_trunc_p (a, b, quotient))
+    return false;
+  *remainder = a - *quotient * b;
+  return true;
+}
+
+/* Return true if there is some polynomial q and constant R such that:
+
+     (1) a = B * q + R
+     (2) |B * q| <= |a|
+     (3) |R| < |B|
+
+   Store the value q in *QUOTIENT if so.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cq>
+inline typename if_nonpoly<Cb, bool>::type
+can_div_trunc_p (const poly_int_pod<N, Ca> &a, Cb b,
+                poly_int_pod<N, Cq> *quotient)
+{
+  /* The remainder must be constant.  */
+  for (unsigned int i = 1; i < N; ++i)
+    if (a.coeffs[i] % b != 0)
+      return false;
+  for (unsigned int i = 0; i < N; ++i)
+    quotient->coeffs[i] = a.coeffs[i] / b;
+  return true;
+}
+
+/* Likewise, but also store R in *REMAINDER.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cq, typename Cr>
+inline typename if_nonpoly<Cb, bool>::type
+can_div_trunc_p (const poly_int_pod<N, Ca> &a, Cb b,
+                poly_int_pod<N, Cq> *quotient, Cr *remainder)
+{
+  if (!can_div_trunc_p (a, b, quotient))
+    return false;
+  *remainder = a.coeffs[0] % b;
+  return true;
+}
+
+/* Return true if there is some constant Q and polynomial r such that:
+
+     (1) a = b * Q + r
+     (2) |a| <= |b * Q|
+     (3) |r| < |b|
+
+   Store the value Q in *QUOTIENT if so.  */
+
+template<unsigned int N, typename Ca, typename Cb, typename Cq>
+inline typename if_nonpoly<Cq, bool>::type
+can_div_away_from_zero_p (const poly_int_pod<N, Ca> &a,
+                         const poly_int_pod<N, Cb> &b,
+                         Cq *quotient)
+{
+  if (!can_div_trunc_p (a, b, quotient))
+    return false;
+  if (maybe_ne (*quotient * b, a))
+    *quotient += (*quotient < 0 ? -1 : 1);
+  return true;
+}
+
+/* Use print_dec to print VALUE to FILE, where SGN is the sign
+   of the values.  */
+
+template<unsigned int N, typename C>
+void
+print_dec (const poly_int_pod<N, C> &value, FILE *file, signop sgn)
+{
+  if (value.is_constant ())
+    print_dec (value.coeffs[0], file, sgn);
+  else
+    {
+      fprintf (file, "[");
+      for (unsigned int i = 0; i < N; ++i)
+       {
+         print_dec (value.coeffs[i], file, sgn);
+         fputc (i == N - 1 ? ']' : ',', file);
+       }
+    }
+}
+
+/* Likewise without the signop argument, for coefficients that have an
+   inherent signedness.  */
+
+template<unsigned int N, typename C>
+void
+print_dec (const poly_int_pod<N, C> &value, FILE *file)
+{
+  STATIC_ASSERT (poly_coeff_traits<C>::signedness >= 0);
+  print_dec (value, file,
+            poly_coeff_traits<C>::signedness ? SIGNED : UNSIGNED);
+}
+
+/* Helper for correctly comparing Pos - Start with Size in cases where
+   known_ge (Pos, Start), Pos and Start are potentially signed, and Size is
+   potentially unsigned.  Applying the cast function to the result of
+   Pos - Start gives the value that should be compared with the size.
+
+   Try to avoid doing any unnecessary arithmetic or copying.  */
+template<typename Pos, typename Start, typename Size,
+        typename Diff = POLY_BINARY_COEFF (Start, Pos),
+        typename Res = POLY_BINARY_COEFF (Size, Diff)>
+struct poly_span_traits
+{
+  /* Assume no cast is needed.  We'll get a warning about signed vs.
+     unsigned comparisons if the assumption is wrong.  */
+  template<typename T>
+  static const T &cast (const T &x) { return x; }
+};
+
+/* The only case a change in type is needed is this one, in which the
+   subtraction would give a HOST_WIDE_INT-based result if done on poly_ints
+   and adding a zero size would give an unsigned HOST_WIDE_INT-based
+   result.  Since we know known_ge (Pos, Start), it is safe to treat
+   Pos - Start as an unsigned HOST_WIDE_INT.  */
+template<typename T1, typename T2, typename T3>
+struct poly_span_traits<T1, T2, T3, HOST_WIDE_INT, unsigned HOST_WIDE_INT>
+{
+  template<typename T>
+  static typename if_nonpoly<T, unsigned HOST_WIDE_INT>::type
+  cast (const T &x) { return x; }
+
+  template<unsigned int N, typename T>
+  static poly_int<N, unsigned HOST_WIDE_INT>
+  cast (const poly_int_pod<N, T> &x) { return x; }
+};
+
+/* Return true if SIZE represents a known size, assuming that all-ones
+   indicates an unknown size.  */
+
+template<typename T>
+inline bool
+known_size_p (const T &a)
+{
+  return maybe_ne (a, POLY_INT_TYPE (T) (-1));
+}
+
+/* Return true if range [POS, POS + SIZE) might include VAL.
+   SIZE can be the special value -1, in which case the range is
+   open-ended.  */
+
+template<typename T1, typename T2, typename T3>
+inline bool
+maybe_in_range_p (const T1 &val, const T2 &pos, const T3 &size)
+{
+  typedef poly_span_traits<T1, T2, T3> span;
+  if (known_lt (val, pos))
+    return false;
+  if (!known_size_p (size))
+    return true;
+  if ((poly_int_traits<T1>::num_coeffs > 1
+       || poly_int_traits<T2>::num_coeffs > 1)
+      && maybe_lt (val, pos))
+    /* In this case we don't know whether VAL >= POS is true at compile
+       time, so we can't prove that VAL >= POS + SIZE.  */
+    return true;
+  return maybe_lt (span::cast (val - pos), size);
+}
+
+/* Return true if range [POS, POS + SIZE) is known to include VAL.
+   SIZE can be the special value -1, in which case the range is
+   open-ended.  */
+
+template<typename T1, typename T2, typename T3>
+inline bool
+known_in_range_p (const T1 &val, const T2 &pos, const T3 &size)
+{
+  typedef poly_span_traits<T1, T2, T3> span;
+  return (known_size_p (size)
+         && known_ge (val, pos)
+         && known_lt (span::cast (val - pos), size));
+}
+
+/* Return true if the two ranges [POS1, POS1 + SIZE1) and [POS2, POS2 + SIZE2)
+   might overlap.  SIZE1 and/or SIZE2 can be the special value -1, in which
+   case the range is open-ended.  */
+
+template<typename T1, typename T2, typename T3, typename T4>
+inline bool
+ranges_maybe_overlap_p (const T1 &pos1, const T2 &size1,
+                       const T3 &pos2, const T4 &size2)
+{
+  if (maybe_in_range_p (pos2, pos1, size1))
+    return maybe_ne (size2, POLY_INT_TYPE (T4) (0));
+  if (maybe_in_range_p (pos1, pos2, size2))
+    return maybe_ne (size1, POLY_INT_TYPE (T2) (0));
+  return false;
+}
+
+/* Return true if the two ranges [POS1, POS1 + SIZE1) and [POS2, POS2 + SIZE2)
+   are known to overlap.  SIZE1 and/or SIZE2 can be the special value -1,
+   in which case the range is open-ended.  */
+
+template<typename T1, typename T2, typename T3, typename T4>
+inline bool
+ranges_known_overlap_p (const T1 &pos1, const T2 &size1,
+                       const T3 &pos2, const T4 &size2)
+{
+  typedef poly_span_traits<T1, T3, T2> span1;
+  typedef poly_span_traits<T1, T3, T4> span2;
+  /* known_gt (POS1 + SIZE1, POS2)                         [infinite precision]
+     --> known_gt (SIZE1, POS2 - POS1)                     [infinite precision]
+     --> known_gt (SIZE1, POS2 - lower_bound (POS1, POS2)) [infinite precision]
+                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ always nonnegative
+     --> known_gt (SIZE1, span1::cast (POS2 - lower_bound (POS1, POS2))).
+
+     Using the saturating subtraction enforces that SIZE1 must be
+     nonzero, since known_gt (0, x) is false for all nonnegative x.
+     If POS2.coeff[I] < POS1.coeff[I] for some I > 0, increasing
+     indeterminate number I makes the unsaturated condition easier to
+     satisfy, so using a saturated coefficient of zero tests the case in
+     which the indeterminate is zero (the minimum value).  */
+  return (known_size_p (size1)
+         && known_size_p (size2)
+         && known_lt (span1::cast (pos2 - lower_bound (pos1, pos2)), size1)
+         && known_lt (span2::cast (pos1 - lower_bound (pos1, pos2)), size2));
+}
+
+/* Return true if range [POS1, POS1 + SIZE1) is known to be a subrange of
+   [POS2, POS2 + SIZE2).  SIZE1 and/or SIZE2 can be the special value -1,
+   in which case the range is open-ended.  */
+
+template<typename T1, typename T2, typename T3, typename T4>
+inline bool
+known_subrange_p (const T1 &pos1, const T2 &size1,
+                 const T3 &pos2, const T4 &size2)
+{
+  typedef typename poly_int_traits<T2>::coeff_type C2;
+  typedef POLY_BINARY_COEFF (T2, T4) size_diff_type;
+  typedef poly_span_traits<T1, T3, size_diff_type> span;
+  return (known_gt (size1, POLY_INT_TYPE (T2) (0))
+         && (poly_coeff_traits<C2>::signedness > 0
+             || known_size_p (size1))
+         && known_size_p (size2)
+         && known_ge (pos1, pos2)
+         && known_le (size1, size2)
+         && known_le (span::cast (pos1 - pos2), size2 - size1));
+}
+
+/* Return true if the endpoint of the range [POS, POS + SIZE) can be
+   stored in a T, or if SIZE is the special value -1, which makes the
+   range open-ended.  */
+
+template<typename T>
+inline typename if_nonpoly<T, bool>::type
+endpoint_representable_p (const T &pos, const T &size)
+{
+  return (!known_size_p (size)
+         || pos <= poly_coeff_traits<T>::max_value - size);
+}
+
+template<unsigned int N, typename C>
+inline bool
+endpoint_representable_p (const poly_int_pod<N, C> &pos,
+                         const poly_int_pod<N, C> &size)
+{
+  if (known_size_p (size))
+    for (unsigned int i = 0; i < N; ++i)
+      if (pos.coeffs[i] > poly_coeff_traits<C>::max_value - size.coeffs[i])
+       return false;
+  return true;
+}
+
+template<unsigned int N, typename C>
+void
+gt_ggc_mx (poly_int_pod<N, C> *)
+{
+}
+
+template<unsigned int N, typename C>
+void
+gt_pch_nx (poly_int_pod<N, C> *)
+{
+}
+
+template<unsigned int N, typename C>
+void
+gt_pch_nx (poly_int_pod<N, C> *, void (*) (void *, void *), void *)
+{
+}
+
+#undef POLY_SET_COEFF
+#undef POLY_INT_TYPE
+#undef POLY_BINARY_COEFF
+#undef CONST_CONST_RESULT
+#undef POLY_CONST_RESULT
+#undef CONST_POLY_RESULT
+#undef POLY_POLY_RESULT
+#undef POLY_CONST_COEFF
+#undef CONST_POLY_COEFF
+#undef POLY_POLY_COEFF
+
+#endif
index 68b2e8ebfc526f96cfb15f9f293a8d5fcb8eeafd..ab8a7c0c71c4ac6b1e78102ff1d584e271ee7219 100644 (file)
@@ -281,6 +281,25 @@ extern int num_passes;
     ::selftest::fail ((LOC), desc_);                          \
   SELFTEST_END_STMT
 
+/* Evaluate EXPECTED and ACTUAL and compare them with known_eq, calling
+   ::selftest::pass if they are always equal,
+   ::selftest::fail if they might be non-equal.  */
+
+#define ASSERT_KNOWN_EQ(EXPECTED, ACTUAL) \
+  ASSERT_KNOWN_EQ_AT ((SELFTEST_LOCATION), (EXPECTED), (ACTUAL))
+
+/* Like ASSERT_KNOWN_EQ, but treat LOC as the effective location of the
+   selftest.  */
+
+#define ASSERT_KNOWN_EQ_AT(LOC, EXPECTED, ACTUAL)                      \
+  SELFTEST_BEGIN_STMT                                                  \
+  const char *desc = "ASSERT_KNOWN_EQ (" #EXPECTED ", " #ACTUAL ")";   \
+  if (known_eq (EXPECTED, ACTUAL))                                     \
+    ::selftest::pass ((LOC), desc);                                    \
+  else                                                                 \
+    ::selftest::fail ((LOC), desc);                                    \
+  SELFTEST_END_STMT
+
 /* Evaluate EXPECTED and ACTUAL and compare them with !=, calling
    ::selftest::pass if they are non-equal,
    ::selftest::fail if they are equal.  */
@@ -294,6 +313,25 @@ extern int num_passes;
     ::selftest::fail (SELFTEST_LOCATION, desc_);              \
   SELFTEST_END_STMT
 
+/* Evaluate EXPECTED and ACTUAL and compare them with maybe_ne, calling
+   ::selftest::pass if they might be non-equal,
+   ::selftest::fail if they are known to be equal.  */
+
+#define ASSERT_MAYBE_NE(EXPECTED, ACTUAL) \
+  ASSERT_MAYBE_NE_AT ((SELFTEST_LOCATION), (EXPECTED), (ACTUAL))
+
+/* Like ASSERT_MAYBE_NE, but treat LOC as the effective location of the
+   selftest.  */
+
+#define ASSERT_MAYBE_NE_AT(LOC, EXPECTED, ACTUAL)                      \
+  SELFTEST_BEGIN_STMT                                                  \
+  const char *desc = "ASSERT_MAYBE_NE (" #EXPECTED ", " #ACTUAL ")";   \
+  if (maybe_ne (EXPECTED, ACTUAL))                                     \
+    ::selftest::pass ((LOC), desc);                                    \
+  else                                                                 \
+    ::selftest::fail ((LOC), desc);                                    \
+  SELFTEST_END_STMT
+
 /* Evaluate EXPECTED and ACTUAL and compare them with strcmp, calling
    ::selftest::pass if they are equal,
    ::selftest::fail if they are non-equal.  */
index b9b45991000c253cf0420004ec080db60191038b..78577d6bf84e9eca0838b784436b56659bdcb178 100644 (file)
@@ -3784,6 +3784,14 @@ candidate as a replacement for the if-convertible sequence described in\n\
 bool, (rtx_insn *seq, struct noce_if_info *if_info),
 default_noce_conversion_profitable_p)
 
+DEFHOOK
+(estimated_poly_value,
+ "Return an estimate of the runtime value of @var{val}, for use in\n\
+things like cost calculations or profiling frequencies.  The default\n\
+implementation returns the lowest possible value of @var{val}.",
+ HOST_WIDE_INT, (poly_int64 val),
+ default_estimated_poly_value)
+
 /* Permit speculative instructions in delay slots during delayed-branch 
    scheduling.  */
 DEFHOOK
index 62601933338497837948744c50fc9859ef05d82a..9696b4d61e1d0e5e85a28d1b8b1509f918a80b0a 100644 (file)
@@ -211,6 +211,21 @@ typedef auto_vec<unsigned short, 32> auto_vec_perm_indices;
 
 extern struct gcc_target targetm;
 
+/* Return an estimate of the runtime value of X, for use in things
+   like cost calculations or profiling frequencies.  Note that this
+   function should never be used in situations where the actual
+   runtime value is needed for correctness, since the function only
+   provides a rough guess.  */
+
+static inline HOST_WIDE_INT
+estimated_poly_value (poly_int64 x)
+{
+  if (NUM_POLY_INT_COEFFS == 1)
+    return x.coeffs[0];
+  else
+    return targetm.estimated_poly_value (x);
+}
+
 #ifdef GCC_TM_H
 
 #ifndef CUMULATIVE_ARGS_MAGIC
index 0edc57b0a156a698a11f9a4b7d78a5709381f324..6b3279e4b38140c2246b302481c1905cb284751e 100644 (file)
@@ -1666,6 +1666,14 @@ default_slow_unaligned_access (machine_mode, unsigned int)
   return STRICT_ALIGNMENT;
 }
 
+/* The default implementation of TARGET_ESTIMATED_POLY_VALUE.  */
+
+HOST_WIDE_INT
+default_estimated_poly_value (poly_int64 x)
+{
+  return x.coeffs[0];
+}
+
 /* For hooks which use the MOVE_RATIO macro, this gives the legacy default
    behavior.  SPEED_P is true if we are compiling for speed.  */
 
index e431934cd601b46e6d4919ba919d3bd06997f505..4c6c65cd312892cbba611054d4b39fefb9620e06 100644 (file)
@@ -210,6 +210,7 @@ extern int default_memory_move_cost (machine_mode, reg_class_t, bool);
 extern int default_register_move_cost (machine_mode, reg_class_t,
                                       reg_class_t);
 extern bool default_slow_unaligned_access (machine_mode, unsigned int);
+extern HOST_WIDE_INT default_estimated_poly_value (poly_int64);
 
 extern bool default_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT,
                                                    unsigned int,
index 4529bcaa185427a0d8248bded779d71ef2b8663a..b80b2f2bf55e5494eb36b776133e5231cd22e223 100644 (file)
@@ -1,3 +1,18 @@
+2017-12-14  Richard Sandiford  <richard.sandiford@linaro.org>
+           Alan Hayward  <alan.hayward@arm.com>
+           David Sherwood  <david.sherwood@arm.com>
+
+       * gcc.dg/plugin/poly-int-tests.h,
+       gcc.dg/plugin/poly-int-test-1.c,
+       gcc.dg/plugin/poly-int-01_plugin.c,
+       gcc.dg/plugin/poly-int-02_plugin.c,
+       gcc.dg/plugin/poly-int-03_plugin.c,
+       gcc.dg/plugin/poly-int-04_plugin.c,
+       gcc.dg/plugin/poly-int-05_plugin.c,
+       gcc.dg/plugin/poly-int-06_plugin.c,
+       gcc.dg/plugin/poly-int-07_plugin.c: New tests.
+       * gcc.dg/plugin/plugin.exp: Run them.
+
 2017-12-13  Peter Bergner  <bergner@vnet.ibm.com>
 
        * gcc.target/powerpc/cpu-builtin-1.c (htm-no-suspend): Add test.
index ff3c976483522bae08d7eef2d3f4d423cd4b0fe6..057f4e223dfdc12a3c3edea0a7b3f3484fde0817 100644 (file)
@@ -62,6 +62,13 @@ set plugin_test_list [list \
     { start_unit_plugin.c start_unit-test-1.c } \
     { finish_unit_plugin.c finish_unit-test-1.c } \
     { wide-int_plugin.c wide-int-test-1.c } \
+    { poly-int-01_plugin.c poly-int-test-1.c } \
+    { poly-int-02_plugin.c poly-int-test-1.c } \
+    { poly-int-03_plugin.c poly-int-test-1.c } \
+    { poly-int-04_plugin.c poly-int-test-1.c } \
+    { poly-int-05_plugin.c poly-int-test-1.c } \
+    { poly-int-06_plugin.c poly-int-test-1.c } \
+    { poly-int-07_plugin.c poly-int-test-1.c } \
     { diagnostic_plugin_test_show_locus.c \
          diagnostic-test-show-locus-bw.c \
          diagnostic-test-show-locus-color.c \
diff --git a/gcc/testsuite/gcc.dg/plugin/poly-int-01_plugin.c b/gcc/testsuite/gcc.dg/plugin/poly-int-01_plugin.c
new file mode 100644 (file)
index 0000000..099c9d9
--- /dev/null
@@ -0,0 +1,21 @@
+/* Not worth spending time optimizing this.  */
+/* { dg-options "-O0" } */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "poly-int-tests.h"
+
+int plugin_is_GPL_compatible;
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+            struct plugin_gcc_version *version)
+{
+  test_helper ();
+  test_poly_coeff_traits ();
+  test_nonpoly ();
+  test_endpoint_representable ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/poly-int-02_plugin.c b/gcc/testsuite/gcc.dg/plugin/poly-int-02_plugin.c
new file mode 100644 (file)
index 0000000..bf103ac
--- /dev/null
@@ -0,0 +1,18 @@
+/* Not worth spending time optimizing this.  */
+/* { dg-options "-O0" } */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "poly-int-tests.h"
+
+int plugin_is_GPL_compatible;
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+            struct plugin_gcc_version *version)
+{
+  test_num_coeffs_core<1> ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/poly-int-03_plugin.c b/gcc/testsuite/gcc.dg/plugin/poly-int-03_plugin.c
new file mode 100644 (file)
index 0000000..0c08ead
--- /dev/null
@@ -0,0 +1,18 @@
+/* Not worth spending time optimizing this.  */
+/* { dg-options "-O0" } */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "poly-int-tests.h"
+
+int plugin_is_GPL_compatible;
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+            struct plugin_gcc_version *version)
+{
+  test_num_coeffs_extra<1> ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/poly-int-04_plugin.c b/gcc/testsuite/gcc.dg/plugin/poly-int-04_plugin.c
new file mode 100644 (file)
index 0000000..8b0a5f9
--- /dev/null
@@ -0,0 +1,18 @@
+/* Not worth spending time optimizing this.  */
+/* { dg-options "-O0" } */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "poly-int-tests.h"
+
+int plugin_is_GPL_compatible;
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+            struct plugin_gcc_version *version)
+{
+  test_num_coeffs_core<2> ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/poly-int-05_plugin.c b/gcc/testsuite/gcc.dg/plugin/poly-int-05_plugin.c
new file mode 100644 (file)
index 0000000..6249311
--- /dev/null
@@ -0,0 +1,18 @@
+/* Not worth spending time optimizing this.  */
+/* { dg-options "-O0" } */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "poly-int-tests.h"
+
+int plugin_is_GPL_compatible;
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+            struct plugin_gcc_version *version)
+{
+  test_num_coeffs_extra<2> ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/poly-int-06_plugin.c b/gcc/testsuite/gcc.dg/plugin/poly-int-06_plugin.c
new file mode 100644 (file)
index 0000000..ee4308c
--- /dev/null
@@ -0,0 +1,26 @@
+/* Not worth spending time optimizing this.  */
+/* { dg-options "-O0" } */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "poly-int-tests.h"
+
+int plugin_is_GPL_compatible;
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+            struct plugin_gcc_version *version)
+{
+  test_signed_2<int> ();
+  test_signed_2<HOST_WIDE_INT> ();
+  test_signed_2<offset_int> ();
+  test_signed_2<widest_int> ();
+
+  test_ordered_2<unsigned short> ();
+  test_ordered_2<unsigned int> ();
+  test_ordered_2<unsigned HOST_WIDE_INT> ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/poly-int-07_plugin.c b/gcc/testsuite/gcc.dg/plugin/poly-int-07_plugin.c
new file mode 100644 (file)
index 0000000..e3203d9
--- /dev/null
@@ -0,0 +1,18 @@
+/* Not worth spending time optimizing this.  */
+/* { dg-options "-O" } */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "poly-int-tests.h"
+
+int plugin_is_GPL_compatible;
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+            struct plugin_gcc_version *version)
+{
+  test_num_coeffs_core<3> ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/poly-int-test-1.c b/gcc/testsuite/gcc.dg/plugin/poly-int-test-1.c
new file mode 100644 (file)
index 0000000..fe284d5
--- /dev/null
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+int
+main (int argc, char **argv)
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/poly-int-tests.h b/gcc/testsuite/gcc.dg/plugin/poly-int-tests.h
new file mode 100644 (file)
index 0000000..b195f67
--- /dev/null
@@ -0,0 +1,4778 @@
+/* This file contains templated tests that are then instantiated in
+   multiple plugin tests, in order to reduce the size of each test.  */
+
+#define ASSERT_FALSE(X) gcc_assert (!(X))
+#define ASSERT_TRUE(X) gcc_assert (X)
+#define ASSERT_EQ(X, Y) gcc_assert ((X) == (Y))
+#define ASSERT_KNOWN_EQ(X, Y) gcc_assert (known_eq (X, Y))
+#define ASSERT_MAYBE_NE(X, Y) gcc_assert (maybe_ne (X, Y))
+
+/* make (X) converts an X of type int into T, using an arbitrary
+   precision for wide_int.  It passes other types of X through as-is.  */
+template<typename T>
+struct coeff_helper
+{
+  static inline const T &make (const T &x) { return x; }
+};
+
+template<>
+struct coeff_helper<wide_int>
+{
+  template<typename T>
+  static inline const T &make (const T &x) { return x; }
+  static inline wide_int make (int i) { return wi::shwi (i, 77); }
+};
+
+/* make (C1, C2, C3) constructs a T using coefficients from C1, C2 and C3,
+   picking only enough to fill the T.  */
+template<typename T>
+struct poly_helper
+{
+  typedef typename poly_int_traits<T>::coeff_type C;
+  template<typename T1, typename T2, typename T3>
+  static T make (const T1 &a, const T2 &b, const T3 &c);
+};
+
+template<typename T>
+template<typename T1, typename T2, typename T3>
+inline T
+poly_helper<T>::make (const T1 &a, const T2 &b, const T3 &c)
+{
+  T res;
+  res = coeff_helper<C>::make (a);
+  if (poly_int_traits<T>::num_coeffs >= 2)
+    res.coeffs[1] = coeff_helper<C>::make (b);
+  if (poly_int_traits<T>::num_coeffs >= 3)
+    res.coeffs[2] = coeff_helper<C>::make (c);
+  return res;
+}
+
+/* Test the helper,  */
+
+static void
+test_helper ()
+{
+  typedef poly_helper< poly_int<1, int> > p1;
+  typedef poly_helper< poly_int<2, int> > p2;
+  typedef poly_helper< poly_int<3, int> > p3;
+
+  ASSERT_MAYBE_NE (p1::make (1, 2, 3), 0);
+  ASSERT_KNOWN_EQ (p1::make (1, 2, 3) - p1::make (1, 0, 0), 0);
+  ASSERT_KNOWN_EQ (p1::make (1, 2, 3) - p1::make (1, 2, 0), 0);
+  ASSERT_KNOWN_EQ (p1::make (1, 2, 3) - p1::make (1, 2, 3), 0);
+
+  ASSERT_MAYBE_NE (p2::make (1, 2, 3), 0);
+  ASSERT_MAYBE_NE (p2::make (1, 2, 3) - p2::make (1, 0, 0), 0);
+  ASSERT_KNOWN_EQ (p2::make (1, 2, 3) - p2::make (1, 2, 0), 0);
+  ASSERT_KNOWN_EQ (p2::make (1, 2, 3) - p2::make (1, 2, 3), 0);
+
+  ASSERT_MAYBE_NE (p3::make (1, 2, 3), 0);
+  ASSERT_MAYBE_NE (p3::make (1, 2, 3) - p3::make (1, 0, 0), 0);
+  ASSERT_MAYBE_NE (p3::make (1, 2, 3) - p3::make (1, 2, 0), 0);
+  ASSERT_KNOWN_EQ (p3::make (1, 2, 3) - p3::make (1, 2, 3), 0);
+}
+
+/* Test poly_coeff_traits.  */
+
+static void
+test_poly_coeff_traits ()
+{
+  ASSERT_EQ (poly_coeff_traits<unsigned short>::signedness, 0);
+  ASSERT_EQ (poly_coeff_traits<unsigned short>::max_value, 0xffff);
+
+  ASSERT_EQ (poly_coeff_traits<int>::signedness, 1);
+  ASSERT_EQ (poly_coeff_traits<int>::max_value, INT_MAX);
+
+  ASSERT_EQ (poly_coeff_traits<unsigned int>::signedness, 0);
+  ASSERT_EQ (poly_coeff_traits<unsigned int>::max_value, UINT_MAX);
+
+  ASSERT_EQ (poly_coeff_traits<HOST_WIDE_INT>::signedness, 1);
+  ASSERT_EQ (poly_coeff_traits<HOST_WIDE_INT>::max_value, HOST_WIDE_INT_MAX);
+
+  ASSERT_EQ (poly_coeff_traits<unsigned HOST_WIDE_INT>::signedness, 0);
+  ASSERT_EQ (poly_coeff_traits<unsigned HOST_WIDE_INT>::max_value,
+            HOST_WIDE_INT_M1U);
+
+  ASSERT_EQ (poly_coeff_traits<wide_int>::signedness, -1);
+  ASSERT_EQ (poly_coeff_traits<offset_int>::signedness, 1);
+  ASSERT_EQ (poly_coeff_traits<widest_int>::signedness, 1);
+}
+
+/* Test poly_int_traits.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_poly_int_traits ()
+{
+  /* Check the properties of poly_int_traits<C>.  */
+  ASSERT_FALSE (poly_int_traits<C>::is_poly);
+  ASSERT_EQ (poly_int_traits<C>::num_coeffs, 1);
+  ASSERT_EQ ((C *) 0 - (typename poly_int_traits<C>::coeff_type *) 0, 0);
+
+  /* Check the properties of poly_int_traits<T>.  */
+  ASSERT_TRUE (poly_int_traits<T>::is_poly);
+  ASSERT_EQ (poly_int_traits<T>::num_coeffs, N);
+  ASSERT_EQ ((C *) 0 - (typename poly_int_traits<T>::coeff_type *) 0, 0);
+}
+
+/* Test the handling of constants.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_constants ()
+{
+  typedef coeff_helper<C> ch;
+  T zero, one, two;
+  poly_int<N, unsigned char> two_uc = 2;
+
+  /* Test operator = on C.  */
+  zero = ch::make (0);
+  one = ch::make (1);
+  two = ch::make (2);
+
+  /* Basic tests of known_eq and maybe_ne.  */
+  ASSERT_KNOWN_EQ (zero, ch::make (0));
+  ASSERT_MAYBE_NE (one, ch::make (0));
+  ASSERT_MAYBE_NE (two, ch::make (0));
+  ASSERT_KNOWN_EQ (ch::make (0), zero);
+  ASSERT_MAYBE_NE (ch::make (0), one);
+  ASSERT_MAYBE_NE (ch::make (0), two);
+  ASSERT_KNOWN_EQ (zero, zero);
+  ASSERT_MAYBE_NE (one, zero);
+  ASSERT_MAYBE_NE (two, zero);
+
+  ASSERT_MAYBE_NE (zero, ch::make (1));
+  ASSERT_KNOWN_EQ (one, ch::make (1));
+  ASSERT_MAYBE_NE (two, ch::make (1));
+  ASSERT_MAYBE_NE (ch::make (1), zero);
+  ASSERT_KNOWN_EQ (ch::make (1), one);
+  ASSERT_MAYBE_NE (ch::make (1), two);
+  ASSERT_MAYBE_NE (zero, one);
+  ASSERT_KNOWN_EQ (one, one);
+  ASSERT_MAYBE_NE (two, one);
+
+  ASSERT_MAYBE_NE (zero, ch::make (2));
+  ASSERT_MAYBE_NE (one, ch::make (2));
+  ASSERT_KNOWN_EQ (two, ch::make (2));
+  ASSERT_MAYBE_NE (ch::make (2), zero);
+  ASSERT_MAYBE_NE (ch::make (2), one);
+  ASSERT_KNOWN_EQ (ch::make (2), two);
+  ASSERT_MAYBE_NE (zero, two);
+  ASSERT_MAYBE_NE (one, two);
+  ASSERT_KNOWN_EQ (two, two);
+
+  ASSERT_MAYBE_NE (zero, two_uc);
+  ASSERT_MAYBE_NE (one, two_uc);
+  ASSERT_KNOWN_EQ (two, two_uc);
+  ASSERT_MAYBE_NE (two_uc, zero);
+  ASSERT_MAYBE_NE (two_uc, one);
+  ASSERT_KNOWN_EQ (two_uc, two);
+}
+
+/* Test operator +=.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_plus_equals ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test += on int.  */
+  T add_cm = ph::make (17, 11, 9);
+  add_cm += 14;
+  ASSERT_KNOWN_EQ (add_cm, ph::make (31, 11, 9));
+
+  /* Test += on T.  */
+  T add_pm = ph::make (100, 44, 11);
+  add_pm += ph::make (1, 2, 3);
+  ASSERT_KNOWN_EQ (add_pm, ph::make (101, 46, 14));
+}
+
+/* Test operator -=.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_minus_equals ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test -= on int.  */
+  T sub_cm = ph::make (82, 13, 61);
+  sub_cm -= 76;
+  ASSERT_KNOWN_EQ (sub_cm, ph::make (6, 13, 61));
+
+  /* Test -= on T.  */
+  T sub_pm = ph::make (82, 13, 61);
+  sub_pm -= ph::make (19, 12, 14);
+  ASSERT_KNOWN_EQ (sub_pm, ph::make (63, 1, 47));
+}
+
+/* Test operator *=.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_times_equals ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test *= on int.  */
+  T mul_cm = ph::make (11, 22, 33);
+  mul_cm *= 3;
+  ASSERT_KNOWN_EQ (mul_cm, ph::make (33, 66, 99));
+}
+
+/* Test operator <<=.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_shl_equals ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test <<= on int.  */
+  T shl_cm = ph::make (10, 11, 13);
+  shl_cm <<= 2;
+  ASSERT_KNOWN_EQ (shl_cm, ph::make (40, 44, 52));
+}
+
+/* Test is_constant.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_is_constant ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test is_constant without arguments.  */
+  ASSERT_TRUE (ph::make (1, 0, 0).is_constant ());
+  ASSERT_EQ (ph::make (2, 0, 1).is_constant (), N <= 2);
+  ASSERT_EQ (ph::make (3, 1, 0).is_constant (), N == 1);
+
+  /* Test is_constant with an argument.  */
+  C const_value;
+  ASSERT_TRUE (ph::make (1, 0, 0).is_constant (&const_value));
+  ASSERT_EQ (const_value, 1);
+  ASSERT_EQ (ph::make (2, 0, 1).is_constant (&const_value), N <= 2);
+  ASSERT_EQ (const_value, N <= 2 ? 2 : 1);
+  ASSERT_EQ (ph::make (3, 1, 0).is_constant (&const_value), N == 1);
+  ASSERT_EQ (const_value, 4 - N);
+}
+
+/* Test to_constant.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_to_constant ()
+{
+  typedef poly_helper<T> ph;
+
+  ASSERT_TRUE (ph::make (1, 0, 0).to_constant () == 1);
+  ASSERT_TRUE (ph::make (111, 0, 0).to_constant () == 111);
+}
+
+/* Test addition, both via operators and wi::.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_addition ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test +.  */
+  ASSERT_KNOWN_EQ (ph::make (55, 43, 30) + 1,
+                  ph::make (56, 43, 30));
+  ASSERT_KNOWN_EQ (100 + ph::make (5, 15, 26),
+                  ph::make (105, 15, 26));
+  ASSERT_KNOWN_EQ (ph::make (7, 100, 41) + ph::make (96, 9, 21),
+                  ph::make (103, 109, 62));
+
+  /* Test wi::add.  */
+  ASSERT_KNOWN_EQ (wi::add (ph::make (55, 43, 30), 1),
+                  ph::make (56, 43, 30));
+  ASSERT_KNOWN_EQ (wi::add (100, ph::make (5, 15, 26)),
+                  ph::make (105, 15, 26));
+  ASSERT_KNOWN_EQ (wi::add (ph::make (7, 100, 41), ph::make (96, 9, 21)),
+                  ph::make (103, 109, 62));
+}
+
+/* Test subtraction, both via operators and wi::.  */
+
+template<unsigned int N, typename C, typename RC, typename T>
+static void
+test_subtraction ()
+{
+  typedef poly_helper<T> ph;
+  typedef poly_helper< poly_int<N, RC> > rph;
+  typedef poly_helper< poly_int<N, int> > iph;
+
+  /* Test -.  Cs with a rank lower than HOST_WIDE_INT promote to
+     HOST_WIDE_INT; use rph to capture this.  */
+  ASSERT_KNOWN_EQ (ph::make (64, 49, 36) - 42,
+                  rph::make (22, 49, 36));
+  ASSERT_KNOWN_EQ (11 - ph::make (9, 3, 4),
+                  rph::make (2, -3, -4));
+  ASSERT_KNOWN_EQ (ph::make (100, 200, 300) - ph::make (99, 197, 305),
+                  rph::make (1, 3, -5));
+
+  /* Test wi::sub.  Primitive Cs promote to widest_int; use iph to capture
+     this.  */
+  ASSERT_KNOWN_EQ (wi::sub (ph::make (64, 49, 36), 42),
+                  iph::make (22, 49, 36));
+  ASSERT_KNOWN_EQ (wi::sub (11, ph::make (9, 3, 4)),
+                  iph::make (2, -3, -4));
+  ASSERT_KNOWN_EQ (wi::sub (ph::make (100, 200, 300), ph::make (99, 197, 305)),
+                  iph::make (1, 3, -5));
+}
+
+/* Test negation, both via operators and wi::.  */
+
+template<unsigned int N, typename C, typename RC, typename T>
+static void
+test_negation ()
+{
+  typedef poly_helper<T> ph;
+  typedef poly_helper< poly_int<N, RC> > rph;
+  typedef poly_helper< poly_int<N, int> > iph;
+
+  /* Test unary -.  */
+  ASSERT_KNOWN_EQ (-ph::make (10, 20, 30),
+                  rph::make (-10, -20, -30));
+
+  /* Test wi::neg.  */
+  ASSERT_KNOWN_EQ (wi::neg (ph::make (10, 20, 30)),
+                  iph::make (-10, -20, -30));
+}
+
+/* Test multiplication, both via operators and wi::.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_multiplication ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test *.  */
+  ASSERT_KNOWN_EQ (ph::make (5, 20, 25) * 10,
+                  ph::make (50, 200, 250));
+  ASSERT_KNOWN_EQ (111 * ph::make (7, 6, 5),
+                  ph::make (777, 666, 555));
+
+  /* Test wi::mul.  */
+  ASSERT_KNOWN_EQ (wi::mul (ph::make (5, 20, 25), 10),
+                  ph::make (50, 200, 250));
+  ASSERT_KNOWN_EQ (wi::mul (111, ph::make (7, 6, 5)),
+                  ph::make (777, 666, 555));
+}
+
+/* Test shift left, both via operators and wi::.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_shift_left ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test <<.  */
+  ASSERT_KNOWN_EQ (ph::make (1, 20, 300) << 4,
+                  ph::make (16, 320, 4800));
+
+  /* Test wi::lshift.  */
+  ASSERT_KNOWN_EQ (wi::lshift (ph::make (9, 15, 50), 3),
+                  ph::make (72, 120, 400));
+}
+
+/* Test maybe_ne.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_maybe_ne ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_ne (T, C).  */
+  ASSERT_EQ (maybe_ne (ph::make (1, 0, 2), ch::make (1)), N == 3);
+  ASSERT_EQ (maybe_ne (ph::make (-11, -2, 0), ch::make (-11)), N >= 2);
+  ASSERT_TRUE (maybe_ne (ph::make (199, 0, 0), ch::make (200)));
+
+  /* Test maybe_ne (C, T).  */
+  ASSERT_EQ (maybe_ne (ch::make (-22), ph::make (-22, 0, -1)), N == 3);
+  ASSERT_EQ (maybe_ne (ch::make (5), ph::make (5, 4, 0)), N >= 2);
+  ASSERT_TRUE (maybe_ne (ch::make (-3), ph::make (-4, 0, 0)));
+
+  /* Test maybe_ne (T, T).  */
+  ASSERT_EQ (maybe_ne (ph::make (1, 3, 5),
+                      ph::make (1, 3, 6)), N == 3);
+  ASSERT_EQ (maybe_ne (ph::make (1, 3, 5),
+                      ph::make (1, 4, 5)), N >= 2);
+  ASSERT_TRUE (maybe_ne (ph::make (1, 3, 5),
+                        ph::make (0, 3, 5)));
+}
+
+/* Test known_eq.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_known_eq ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_eq (T, C).  */
+  ASSERT_EQ (known_eq (ph::make (1, 0, 2), ch::make (1)), N <= 2);
+  ASSERT_EQ (known_eq (ph::make (-11, -2, 0), ch::make (-11)), N == 1);
+  ASSERT_FALSE (known_eq (ph::make (199, 0, 0), ch::make (200)));
+
+  /* Test known_eq (C, T).  */
+  ASSERT_EQ (known_eq (ch::make (-22), ph::make (-22, 0, -1)), N <= 2);
+  ASSERT_EQ (known_eq (ch::make (5), ph::make (5, 4, 0)), N == 1);
+  ASSERT_FALSE (known_eq (ch::make (-3), ph::make (-4, 0, 0)));
+
+  /* Test known_eq (T, T).  */
+  ASSERT_EQ (known_eq (ph::make (1, 3, 5),
+                      ph::make (1, 3, 6)), N <= 2);
+  ASSERT_EQ (known_eq (ph::make (1, 3, 5),
+                      ph::make (1, 4, 5)), N == 1);
+  ASSERT_FALSE (known_eq (ph::make (1, 3, 5),
+                         ph::make (0, 3, 5)));
+}
+
+/* Test can_align_p.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_can_align_p ()
+{
+  typedef poly_helper<T> ph;
+
+  ASSERT_TRUE (can_align_p (ph::make (41, 32, 16), 16));
+  ASSERT_EQ (can_align_p (ph::make (15, 64, 8), 16), N <= 2);
+  ASSERT_EQ (can_align_p (ph::make (17, 8, 80), 16), N == 1);
+  ASSERT_TRUE (can_align_p (ph::make (-39, -64, -32), 32));
+  ASSERT_EQ (can_align_p (ph::make (-32, -96, -31), 32), N <= 2);
+  ASSERT_EQ (can_align_p (ph::make (-31, -31, -128), 32), N == 1);
+  ASSERT_TRUE (can_align_p (ph::make (17, 0, 0), 16));
+  ASSERT_TRUE (can_align_p (ph::make (16, 0, 0), 16));
+  ASSERT_TRUE (can_align_p (ph::make (15, 0, 0), 16));
+  ASSERT_TRUE (can_align_p (ph::make (-17, 0, 0), 16));
+  ASSERT_TRUE (can_align_p (ph::make (-16, 0, 0), 16));
+  ASSERT_TRUE (can_align_p (ph::make (-15, 0, 0), 16));
+}
+
+/* Test can_align_up.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_can_align_up ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  T aligned;
+  ASSERT_TRUE (can_align_up (ph::make (41, 32, 16), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ph::make (48, 32, 16));
+  ASSERT_EQ (can_align_up (ph::make (15, 64, 8), 16, &aligned), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (aligned, ph::make (16, 64, 0));
+  ASSERT_EQ (can_align_up (ph::make (17, 8, 80), 16, &aligned), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (aligned, ch::make (32));
+  ASSERT_TRUE (can_align_up (ph::make (-39, -64, -32), 32, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ph::make (-32, -64, -32));
+  ASSERT_EQ (can_align_up (ph::make (-32, -96, -31), 32, &aligned), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (aligned, ph::make (-32, -96, 0));
+  ASSERT_EQ (can_align_up (ph::make (-31, -31, -128), 32, &aligned), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (aligned, ch::make (0));
+  ASSERT_TRUE (can_align_up (ph::make (17, 0, 0), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ch::make (32));
+  ASSERT_TRUE (can_align_up (ph::make (16, 0, 0), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ch::make (16));
+  ASSERT_TRUE (can_align_up (ph::make (15, 0, 0), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ch::make (16));
+  ASSERT_TRUE (can_align_up (ph::make (-17, 0, 0), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ch::make (-16));
+  ASSERT_TRUE (can_align_up (ph::make (-16, 0, 0), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ch::make (-16));
+  ASSERT_TRUE (can_align_up (ph::make (-15, 0, 0), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ch::make (0));
+}
+
+/* Test can_align_down.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_can_align_down ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  T aligned;
+  ASSERT_TRUE (can_align_down (ph::make (41, 32, 16), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ph::make (32, 32, 16));
+  ASSERT_EQ (can_align_down (ph::make (15, 64, 8), 16, &aligned), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (aligned, ph::make (0, 64, 0));
+  ASSERT_EQ (can_align_down (ph::make (17, 8, 80), 16, &aligned), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (aligned, ch::make (16));
+  ASSERT_TRUE (can_align_down (ph::make (-39, -64, -32), 32, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ph::make (-64, -64, -32));
+  ASSERT_EQ (can_align_down (ph::make (-32, -96, -31), 32, &aligned), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (aligned, ph::make (-32, -96, 0));
+  ASSERT_EQ (can_align_down (ph::make (-31, -31, -128), 32, &aligned), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (aligned, ch::make (-32));
+  ASSERT_TRUE (can_align_down (ph::make (17, 0, 0), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ch::make (16));
+  ASSERT_TRUE (can_align_down (ph::make (16, 0, 0), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ch::make (16));
+  ASSERT_TRUE (can_align_down (ph::make (15, 0, 0), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ch::make (0));
+  ASSERT_TRUE (can_align_down (ph::make (-17, 0, 0), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ch::make (-32));
+  ASSERT_TRUE (can_align_down (ph::make (-16, 0, 0), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ch::make (-16));
+  ASSERT_TRUE (can_align_down (ph::make (-15, 0, 0), 16, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ch::make (-16));
+}
+
+/* Test known_equal_after_align_up.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_known_equal_after_align_up ()
+{
+  typedef poly_helper<T> ph;
+
+  ASSERT_EQ (known_equal_after_align_up (ph::make (15, 15, 32),
+                                        ph::make (16, 15, 32), 16), N == 1);
+  ASSERT_EQ (known_equal_after_align_up (ph::make (16, 16, 15),
+                                        ph::make (15, 16, 15), 16), N <= 2);
+  ASSERT_EQ (known_equal_after_align_up (ph::make (15, 16, 32),
+                                        ph::make (7, 16, 48), 16), N <= 2);
+  ASSERT_EQ (known_equal_after_align_up (ph::make (7, 32, 16),
+                                        ph::make (15, 48, 16), 16), N == 1);
+  ASSERT_TRUE (known_equal_after_align_up (ph::make (16, 16, 32),
+                                          ph::make (15, 16, 32), 16));
+  ASSERT_TRUE (known_equal_after_align_up (ph::make (32, 0, 0),
+                                          ph::make (31, 0, 0), 16));
+  ASSERT_TRUE (known_equal_after_align_up (ph::make (32, 0, 0),
+                                          ph::make (32, 0, 0), 32));
+  ASSERT_FALSE (known_equal_after_align_up (ph::make (32, 0, 0),
+                                           ph::make (33, 0, 0), 16));
+  ASSERT_FALSE (known_equal_after_align_up (ph::make (-31, 0, 0),
+                                           ph::make (-32, 0, 0), 16));
+  ASSERT_TRUE (known_equal_after_align_up (ph::make (-32, 0, 0),
+                                          ph::make (-32, 0, 0), 32));
+  ASSERT_TRUE (known_equal_after_align_up (ph::make (-33, 0, 0),
+                                          ph::make (-32, 0, 0), 16));
+}
+
+/* Test known_equal_after_align_down.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_known_equal_after_align_down ()
+{
+  typedef poly_helper<T> ph;
+
+  ASSERT_EQ (known_equal_after_align_down (ph::make (17, 15, 32),
+                                          ph::make (16, 15, 32), 16), N == 1);
+  ASSERT_EQ (known_equal_after_align_down (ph::make (16, 16, 15),
+                                          ph::make (17, 16, 15), 16), N <= 2);
+  ASSERT_EQ (known_equal_after_align_down (ph::make (15, 16, 32),
+                                          ph::make (7, 16, 48), 16), N <= 2);
+  ASSERT_EQ (known_equal_after_align_down (ph::make (15, 32, 16),
+                                          ph::make (7, 48, 16), 16), N == 1);
+  ASSERT_TRUE (known_equal_after_align_down (ph::make (16, 16, 32),
+                                            ph::make (17, 16, 32), 16));
+  ASSERT_FALSE (known_equal_after_align_down (ph::make (32, 0, 0),
+                                             ph::make (31, 0, 0), 16));
+  ASSERT_TRUE (known_equal_after_align_down (ph::make (32, 0, 0),
+                                            ph::make (32, 0, 0), 32));
+  ASSERT_TRUE (known_equal_after_align_down (ph::make (32, 0, 0),
+                                            ph::make (33, 0, 0), 16));
+  ASSERT_TRUE (known_equal_after_align_down (ph::make (-31, 0, 0),
+                                            ph::make (-32, 0, 0), 16));
+  ASSERT_TRUE (known_equal_after_align_down (ph::make (-32, 0, 0),
+                                            ph::make (-32, 0, 0), 32));
+  ASSERT_FALSE (known_equal_after_align_down (ph::make (-33, 0, 0),
+                                             ph::make (-32, 0, 0), 16));
+}
+
+/* Test force_align_up.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_force_align_up ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test force_align_up.  */
+  ASSERT_KNOWN_EQ (force_align_up (ph::make (41, 32, 16), 16),
+                  ph::make (48, 32, 16));
+  ASSERT_KNOWN_EQ (force_align_up (ph::make (-39, -64, -32), 32),
+                  ph::make (-32, -64, -32));
+  ASSERT_KNOWN_EQ (force_align_up (ph::make (17, 0, 0), 16),
+                  ch::make (32));
+  ASSERT_KNOWN_EQ (force_align_up (ph::make (16, 0, 0), 16),
+                  ch::make (16));
+  ASSERT_KNOWN_EQ (force_align_up (ph::make (15, 0, 0), 16),
+                  ch::make (16));
+  ASSERT_KNOWN_EQ (force_align_up (ph::make (-17, 0, 0), 16),
+                  ch::make (-16));
+  ASSERT_KNOWN_EQ (force_align_up (ph::make (-16, 0, 0), 16),
+                  ch::make (-16));
+  ASSERT_KNOWN_EQ (force_align_up (ph::make (-15, 0, 0), 16),
+                  ch::make (0));
+}
+
+/* Test force_align_down.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_force_align_down ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  ASSERT_KNOWN_EQ (force_align_down (ph::make (41, 32, 16), 16),
+                  ph::make (32, 32, 16));
+  ASSERT_KNOWN_EQ (force_align_down (ph::make (-39, -64, -32), 32),
+                  ph::make (-64, -64, -32));
+  ASSERT_KNOWN_EQ (force_align_down (ph::make (17, 0, 0), 16),
+                  ch::make (16));
+  ASSERT_KNOWN_EQ (force_align_down (ph::make (16, 0, 0), 16),
+                  ch::make (16));
+  ASSERT_KNOWN_EQ (force_align_down (ph::make (15, 0, 0), 16),
+                  ch::make (0));
+  ASSERT_KNOWN_EQ (force_align_down (ph::make (-17, 0, 0), 16),
+                  ch::make (-32));
+  ASSERT_KNOWN_EQ (force_align_down (ph::make (-16, 0, 0), 16),
+                  ch::make (-16));
+  ASSERT_KNOWN_EQ (force_align_down (ph::make (-15, 0, 0), 16),
+                  ch::make (-16));
+}
+
+/* Test aligned_lower_bound.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_aligned_lower_bound ()
+{
+  typedef poly_helper<T> ph;
+
+  ASSERT_KNOWN_EQ (aligned_lower_bound (ph::make (17, 63, 33), 16),
+                  ph::make (16, 48, 32));
+  ASSERT_KNOWN_EQ (aligned_lower_bound (ph::make (11, -33, 64), 32),
+                  ph::make (0, -64, 64));
+  ASSERT_KNOWN_EQ (aligned_lower_bound (ph::make (-9, 16, -31), 8),
+                  ph::make (-16, 16, -32));
+  ASSERT_KNOWN_EQ (aligned_lower_bound (ph::make (-8, -12, 16), 4),
+                  ph::make (-8, -12, 16));
+}
+
+/* Test aligned_upper_bound.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_aligned_upper_bound ()
+{
+  typedef poly_helper<T> ph;
+
+  ASSERT_KNOWN_EQ (aligned_upper_bound (ph::make (17, 63, 33), 16),
+                  ph::make (32, 64, 48));
+  ASSERT_KNOWN_EQ (aligned_upper_bound (ph::make (11, -33, 64), 32),
+                  ph::make (32, -32, 64));
+  ASSERT_KNOWN_EQ (aligned_upper_bound (ph::make (-9, 16, -31), 8),
+                  ph::make (-8, 16, -24));
+  ASSERT_KNOWN_EQ (aligned_upper_bound (ph::make (-8, -12, 16), 4),
+                  ph::make (-8, -12, 16));
+}
+
+/* Test known_misalignment.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_known_misalignment ()
+{
+  typedef poly_helper<T> ph;
+
+  C misalignment;
+  ASSERT_TRUE (known_misalignment (ph::make (45, 8, 24), 8, &misalignment));
+  ASSERT_EQ (misalignment, 5);
+  ASSERT_EQ (known_misalignment (ph::make (17, 16, 23), 8, &misalignment),
+            N <= 2);
+  ASSERT_EQ (misalignment, N <= 2 ? 1 : 5);
+  ASSERT_EQ (known_misalignment (ph::make (31, 15, 0), 16, &misalignment),
+            N == 1);
+  ASSERT_EQ (misalignment, N == 1 ? 15 : N == 2 ? 1 : 5);
+  ASSERT_TRUE (known_misalignment (ph::make (-45, -8, -24), 8, &misalignment));
+  ASSERT_EQ (misalignment, 3);
+  ASSERT_TRUE (known_misalignment (ph::make (-11, 0, 0), 32, &misalignment));
+  ASSERT_EQ (misalignment, 21);
+}
+
+/* Test force_get_misalignment.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_force_get_misalignment ()
+{
+  typedef poly_helper<T> ph;
+
+  ASSERT_EQ (force_get_misalignment (ph::make (45, 8, 24), 8), 5);
+  ASSERT_EQ (force_get_misalignment (ph::make (17, 16, 24), 8), 1);
+  ASSERT_EQ (force_get_misalignment (ph::make (31, -16, 0), 16), 15);
+  ASSERT_EQ (force_get_misalignment (ph::make (-45, -8, -24), 8), 3);
+  ASSERT_EQ (force_get_misalignment (ph::make (-11, 0, 0), 32), 21);
+}
+
+/* Test known_alignment.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_known_alignment ()
+{
+  typedef poly_helper<T> ph;
+
+  ASSERT_EQ (known_alignment (ph::make (16, 24, 30)),
+            N == 1 ? 16 : N == 2 ? 8 : 2);
+  ASSERT_EQ (known_alignment (ph::make (30, 0, 31)),
+            N <= 2 ? 2 : 1);
+  ASSERT_EQ (known_alignment (ph::make (20, 16, 24)), 4);
+  ASSERT_EQ (known_alignment (ph::make (24, 0, 0)), 8);
+  ASSERT_EQ (known_alignment (ph::make (0, 0, 0)), 0);
+  ASSERT_EQ (known_alignment (ph::make (0, 12, 0)),
+            N == 1 ? 0 : 4);
+  ASSERT_EQ (known_alignment (ph::make (0, 12, 6)),
+            N == 1 ? 0 : N == 2 ? 4 : 2);
+  ASSERT_EQ (known_alignment (ph::make (-40, -80, -12)),
+            N <= 2 ? 8 : 4);
+}
+
+/* Test can_ior_p.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_can_ior_p ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  T ior;
+  ASSERT_TRUE (can_ior_p (ph::make (0x87, 0x60, 0xa0), 0x13, &ior));
+  ASSERT_KNOWN_EQ (ior, ph::make (0x97, 0x60, 0xa0));
+  ASSERT_EQ (can_ior_p (ph::make (9, 96, 48), 28, &ior), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (ior, ph::make (29, 96, 0));
+  ASSERT_EQ (can_ior_p (ph::make (0x81, 0x20, 0), 0x44, &ior), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (ior, ch::make (0xc5));
+}
+
+/* Test maybe_eq for poly_int<2, C>.  */
+
+template<typename C>
+static void
+test_maybe_eq_2 ()
+{
+  typedef poly_int<2, C> T;
+
+  /* Test maybe_eq (T, C).  */
+  ASSERT_TRUE (maybe_eq (T (1, 4), 41));
+  ASSERT_FALSE (maybe_eq (T (1, 4), 42));
+  ASSERT_FALSE (maybe_eq (T (1, 4), 40));
+  ASSERT_TRUE (maybe_eq (T (1, 4), 1));
+  ASSERT_FALSE (maybe_eq (T (1, 4), 0));
+  ASSERT_FALSE (maybe_eq (T (1, 4), 2));
+
+  /* Test maybe_eq (C, T).  */
+  ASSERT_TRUE (maybe_eq (20, T (5, 3)));
+  ASSERT_FALSE (maybe_eq (21, T (5, 3)));
+  ASSERT_FALSE (maybe_eq (19, T (5, 3)));
+  ASSERT_TRUE (maybe_eq (5, T (5, 3)));
+  ASSERT_FALSE (maybe_eq (2, T (5, 3)));
+  ASSERT_FALSE (maybe_eq (6, T (5, 3)));
+
+  /* Test maybe_eq (T, T).  */
+  ASSERT_TRUE (maybe_eq (T (2, 5), T (22, 3)));
+  ASSERT_FALSE (maybe_eq (T (3, 5), T (22, 3)));
+  ASSERT_FALSE (maybe_eq (T (2, 5), T (23, 3)));
+  ASSERT_FALSE (maybe_eq (T (2, 5), T (3, 5)));
+  ASSERT_TRUE (maybe_eq (T (10, 3), T (19, 0)));
+  ASSERT_FALSE (maybe_eq (T (10, 3), T (20, 0)));
+  ASSERT_TRUE (maybe_eq (T (10, 0), T (4, 2)));
+  ASSERT_FALSE (maybe_eq (T (11, 0), T (4, 2)));
+}
+
+/* Test known_ne for poly_int<2, C>.  */
+
+template<typename C>
+static void
+test_known_ne_2 ()
+{
+  typedef poly_int<2, C> T;
+
+  /* Test known_ne (T, C).  */
+  ASSERT_FALSE (known_ne (T (1, 4), 41));
+  ASSERT_TRUE (known_ne (T (1, 4), 42));
+  ASSERT_TRUE (known_ne (T (1, 4), 40));
+  ASSERT_FALSE (known_ne (T (1, 4), 1));
+  ASSERT_TRUE (known_ne (T (1, 4), 0));
+  ASSERT_TRUE (known_ne (T (1, 4), 2));
+
+  /* Test known_ne (C, T).  */
+  ASSERT_FALSE (known_ne (20, T (5, 3)));
+  ASSERT_TRUE (known_ne (21, T (5, 3)));
+  ASSERT_TRUE (known_ne (19, T (5, 3)));
+  ASSERT_FALSE (known_ne (5, T (5, 3)));
+  ASSERT_TRUE (known_ne (2, T (5, 3)));
+  ASSERT_TRUE (known_ne (6, T (5, 3)));
+
+  /* Test known_ne (T, T).  */
+  ASSERT_FALSE (known_ne (T (2, 5), T (22, 3)));
+  ASSERT_TRUE (known_ne (T (3, 5), T (22, 3)));
+  ASSERT_TRUE (known_ne (T (2, 5), T (23, 3)));
+  ASSERT_TRUE (known_ne (T (2, 5), T (3, 5)));
+  ASSERT_FALSE (known_ne (T (10, 3), T (19, 0)));
+  ASSERT_TRUE (known_ne (T (10, 3), T (20, 0)));
+  ASSERT_FALSE (known_ne (T (10, 0), T (4, 2)));
+  ASSERT_TRUE (known_ne (T (11, 0), T (4, 2)));
+}
+
+/* Test maybe_le for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_maybe_le ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_le (T, C).  */
+  ASSERT_FALSE (maybe_le (ph::make (7, 5, 4), ch::make (6)));
+  ASSERT_FALSE (maybe_le (ph::make (7, 0, 0), ch::make (6)));
+  ASSERT_TRUE (maybe_le (ph::make (60, 1, 2), ch::make (60)));
+  ASSERT_TRUE (maybe_le (ph::make (60, 0, 0), ch::make (60)));
+  ASSERT_TRUE (maybe_le (ph::make (30, 9, 4), ch::make (31)));
+  ASSERT_TRUE (maybe_le (ph::make (30, 0, 0), ch::make (31)));
+
+  /* Test maybe_le (C, T).  */
+  ASSERT_TRUE (maybe_le (ch::make (6), ph::make (7, 5, 4)));
+  ASSERT_TRUE (maybe_le (ch::make (6), ph::make (7, 0, 0)));
+  ASSERT_TRUE (maybe_le (ch::make (60), ph::make (60, 1, 2)));
+  ASSERT_TRUE (maybe_le (ch::make (60), ph::make (60, 0, 0)));
+  ASSERT_EQ (maybe_le (ch::make (31), ph::make (30, 9, 4)), N >= 2);
+  ASSERT_EQ (maybe_le (ch::make (31), ph::make (30, 0, 4)), N == 3);
+  ASSERT_FALSE (maybe_le (ch::make (31), ph::make (30, 0, 0)));
+
+  /* Test maybe_le (T, T).  */
+  ASSERT_EQ (maybe_le (ph::make (3, 14, 99), ph::make (2, 15, 100)), N >= 2);
+  ASSERT_EQ (maybe_le (ph::make (3, 14, 99), ph::make (2, 13, 100)), N == 3);
+  ASSERT_EQ (maybe_le (ph::make (3, 14, 99), ph::make (2, 15, 98)), N >= 2);
+  ASSERT_FALSE (maybe_le (ph::make (3, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_FALSE (maybe_le (ph::make (3, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_TRUE (maybe_le (ph::make (2, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_TRUE (maybe_le (ph::make (2, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_TRUE (maybe_le (ph::make (2, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_TRUE (maybe_le (ph::make (1, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_TRUE (maybe_le (ph::make (1, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_TRUE (maybe_le (ph::make (1, 14, 99), ph::make (2, 13, 98)));
+}
+
+/* Test maybe_lt for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_maybe_lt ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_lt (T, C).  */
+  ASSERT_FALSE (maybe_lt (ph::make (7, 5, 4), ch::make (6)));
+  ASSERT_FALSE (maybe_lt (ph::make (7, 0, 0), ch::make (6)));
+  ASSERT_FALSE (maybe_lt (ph::make (60, 1, 2), ch::make (60)));
+  ASSERT_FALSE (maybe_lt (ph::make (60, 0, 0), ch::make (60)));
+  ASSERT_TRUE (maybe_lt (ph::make (30, 9, 4), ch::make (31)));
+  ASSERT_TRUE (maybe_lt (ph::make (30, 0, 0), ch::make (31)));
+
+  /* Test maybe_lt (C, T).  */
+  ASSERT_TRUE (maybe_lt (ch::make (6), ph::make (7, 5, 4)));
+  ASSERT_TRUE (maybe_lt (ch::make (6), ph::make (7, 0, 0)));
+  ASSERT_EQ (maybe_lt (ch::make (60), ph::make (60, 1, 2)), N >= 2);
+  ASSERT_EQ (maybe_lt (ch::make (60), ph::make (60, 0, 2)), N == 3);
+  ASSERT_FALSE (maybe_lt (ch::make (60), ph::make (60, 0, 0)));
+  ASSERT_EQ (maybe_lt (ch::make (31), ph::make (30, 9, 4)), N >= 2);
+  ASSERT_EQ (maybe_lt (ch::make (31), ph::make (30, 0, 4)), N == 3);
+  ASSERT_FALSE (maybe_lt (ch::make (31), ph::make (30, 0, 0)));
+
+  /* Test maybe_lt (T, T).  */
+  ASSERT_EQ (maybe_lt (ph::make (3, 14, 99), ph::make (2, 15, 100)), N >= 2);
+  ASSERT_EQ (maybe_lt (ph::make (3, 14, 99), ph::make (2, 13, 100)), N == 3);
+  ASSERT_EQ (maybe_lt (ph::make (3, 14, 99), ph::make (2, 15, 98)), N >= 2);
+  ASSERT_FALSE (maybe_lt (ph::make (3, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_FALSE (maybe_lt (ph::make (3, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_EQ (maybe_lt (ph::make (2, 14, 99), ph::make (2, 15, 100)), N >= 2);
+  ASSERT_EQ (maybe_lt (ph::make (2, 14, 99), ph::make (2, 13, 100)), N == 3);
+  ASSERT_EQ (maybe_lt (ph::make (2, 14, 99), ph::make (2, 15, 98)), N >= 2);
+  ASSERT_FALSE (maybe_lt (ph::make (2, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_FALSE (maybe_lt (ph::make (2, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_TRUE (maybe_lt (ph::make (1, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_TRUE (maybe_lt (ph::make (1, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_TRUE (maybe_lt (ph::make (1, 14, 99), ph::make (2, 13, 98)));
+}
+
+/* Test maybe_ge for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_maybe_ge ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_ge (T, C).  */
+  ASSERT_TRUE (maybe_ge (ph::make (7, 5, 4), ch::make (6)));
+  ASSERT_TRUE (maybe_ge (ph::make (7, 0, 0), ch::make (6)));
+  ASSERT_TRUE (maybe_ge (ph::make (60, 1, 2), ch::make (60)));
+  ASSERT_TRUE (maybe_ge (ph::make (60, 0, 0), ch::make (60)));
+  ASSERT_EQ (maybe_ge (ph::make (30, 9, 4), ch::make (31)), N >= 2);
+  ASSERT_EQ (maybe_ge (ph::make (30, 0, 4), ch::make (31)), N == 3);
+  ASSERT_FALSE (maybe_ge (ph::make (30, 0, 0), ch::make (31)));
+
+  /* Test maybe_ge (C, T).  */
+  ASSERT_FALSE (maybe_ge (ch::make (6), ph::make (7, 5, 4)));
+  ASSERT_FALSE (maybe_ge (ch::make (6), ph::make (7, 0, 0)));
+  ASSERT_TRUE (maybe_ge (ch::make (60), ph::make (60, 1, 2)));
+  ASSERT_TRUE (maybe_ge (ch::make (60), ph::make (60, 0, 0)));
+  ASSERT_TRUE (maybe_ge (ch::make (31), ph::make (30, 9, 4)));
+  ASSERT_TRUE (maybe_ge (ch::make (31), ph::make (30, 0, 0)));
+
+  /* Test maybe_ge (T, T).  */
+  ASSERT_TRUE (maybe_ge (ph::make (3, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_TRUE (maybe_ge (ph::make (3, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_TRUE (maybe_ge (ph::make (3, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_TRUE (maybe_ge (ph::make (2, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_TRUE (maybe_ge (ph::make (2, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_TRUE (maybe_ge (ph::make (2, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_FALSE (maybe_ge (ph::make (1, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_FALSE (maybe_ge (ph::make (1, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_EQ (maybe_ge (ph::make (1, 14, 99), ph::make (2, 15, 98)), N == 3);
+  ASSERT_EQ (maybe_ge (ph::make (1, 14, 99), ph::make (2, 13, 100)), N >= 2);
+  ASSERT_EQ (maybe_ge (ph::make (1, 14, 99), ph::make (2, 13, 98)), N >= 2);
+}
+
+/* Test maybe_gt for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_maybe_gt ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_gt (T, C).  */
+  ASSERT_TRUE (maybe_gt (ph::make (7, 5, 4), ch::make (6)));
+  ASSERT_TRUE (maybe_gt (ph::make (7, 0, 0), ch::make (6)));
+  ASSERT_EQ (maybe_gt (ph::make (60, 1, 2), ch::make (60)), N >= 2);
+  ASSERT_EQ (maybe_gt (ph::make (60, 0, 2), ch::make (60)), N == 3);
+  ASSERT_FALSE (maybe_gt (ph::make (60, 0, 0), ch::make (60)));
+  ASSERT_EQ (maybe_gt (ph::make (30, 9, 4), ch::make (31)), N >= 2);
+  ASSERT_EQ (maybe_gt (ph::make (30, 0, 4), ch::make (31)), N == 3);
+  ASSERT_FALSE (maybe_gt (ph::make (30, 0, 0), ch::make (31)));
+
+  /* Test maybe_gt (C, T).  */
+  ASSERT_FALSE (maybe_gt (ch::make (6), ph::make (7, 5, 4)));
+  ASSERT_FALSE (maybe_gt (ch::make (6), ph::make (7, 0, 0)));
+  ASSERT_FALSE (maybe_gt (ch::make (60), ph::make (60, 1, 2)));
+  ASSERT_FALSE (maybe_gt (ch::make (60), ph::make (60, 0, 0)));
+  ASSERT_TRUE (maybe_gt (ch::make (31), ph::make (30, 9, 4)));
+  ASSERT_TRUE (maybe_gt (ch::make (31), ph::make (30, 0, 0)));
+
+  /* Test maybe_gt (T, T).  */
+  ASSERT_TRUE (maybe_gt (ph::make (3, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_TRUE (maybe_gt (ph::make (3, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_TRUE (maybe_gt (ph::make (3, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_FALSE (maybe_gt (ph::make (2, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_FALSE (maybe_gt (ph::make (2, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_EQ (maybe_gt (ph::make (2, 14, 99), ph::make (2, 15, 98)), N == 3);
+  ASSERT_EQ (maybe_gt (ph::make (2, 14, 99), ph::make (2, 13, 100)), N >= 2);
+  ASSERT_EQ (maybe_gt (ph::make (2, 14, 99), ph::make (2, 13, 98)), N >= 2);
+  ASSERT_FALSE (maybe_gt (ph::make (1, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_FALSE (maybe_gt (ph::make (1, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_EQ (maybe_gt (ph::make (1, 14, 99), ph::make (2, 15, 98)), N == 3);
+  ASSERT_EQ (maybe_gt (ph::make (1, 14, 99), ph::make (2, 13, 100)), N >= 2);
+  ASSERT_EQ (maybe_gt (ph::make (1, 14, 99), ph::make (2, 13, 98)), N >= 2);
+}
+
+/* Test known_gt for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_known_gt ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_gt (T, C).  */
+  ASSERT_TRUE (known_gt (ph::make (7, 5, 4), ch::make (6)));
+  ASSERT_TRUE (known_gt (ph::make (7, 0, 0), ch::make (6)));
+  ASSERT_FALSE (known_gt (ph::make (60, 1, 2), ch::make (60)));
+  ASSERT_FALSE (known_gt (ph::make (60, 0, 0), ch::make (60)));
+  ASSERT_FALSE (known_gt (ph::make (30, 9, 4), ch::make (31)));
+  ASSERT_FALSE (known_gt (ph::make (30, 0, 0), ch::make (31)));
+
+  /* Test known_gt (C, T).  */
+  ASSERT_FALSE (known_gt (ch::make (6), ph::make (7, 5, 4)));
+  ASSERT_FALSE (known_gt (ch::make (6), ph::make (7, 0, 0)));
+  ASSERT_FALSE (known_gt (ch::make (60), ph::make (60, 1, 2)));
+  ASSERT_FALSE (known_gt (ch::make (60), ph::make (60, 0, 0)));
+  ASSERT_EQ (known_gt (ch::make (31), ph::make (30, 9, 4)), N == 1);
+  ASSERT_EQ (known_gt (ch::make (31), ph::make (30, 0, 4)), N <= 2);
+  ASSERT_TRUE (known_gt (ch::make (31), ph::make (30, 0, 0)));
+
+  /* Test known_gt (T, T).  */
+  ASSERT_EQ (known_gt (ph::make (3, 14, 99), ph::make (2, 15, 100)), N == 1);
+  ASSERT_EQ (known_gt (ph::make (3, 14, 99), ph::make (2, 13, 100)), N <= 2);
+  ASSERT_EQ (known_gt (ph::make (3, 14, 99), ph::make (2, 15, 98)), N == 1);
+  ASSERT_TRUE (known_gt (ph::make (3, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_TRUE (known_gt (ph::make (3, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_FALSE (known_gt (ph::make (2, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_FALSE (known_gt (ph::make (2, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_FALSE (known_gt (ph::make (2, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_FALSE (known_gt (ph::make (1, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_FALSE (known_gt (ph::make (1, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_FALSE (known_gt (ph::make (1, 14, 99), ph::make (2, 13, 98)));
+}
+
+/* Test known_ge for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_known_ge ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_ge (T, C).  */
+  ASSERT_TRUE (known_ge (ph::make (7, 5, 4), ch::make (6)));
+  ASSERT_TRUE (known_ge (ph::make (7, 0, 0), ch::make (6)));
+  ASSERT_TRUE (known_ge (ph::make (60, 1, 2), ch::make (60)));
+  ASSERT_TRUE (known_ge (ph::make (60, 0, 0), ch::make (60)));
+  ASSERT_FALSE (known_ge (ph::make (30, 9, 4), ch::make (31)));
+  ASSERT_FALSE (known_ge (ph::make (30, 0, 0), ch::make (31)));
+
+  /* Test known_ge (C, T).  */
+  ASSERT_FALSE (known_ge (ch::make (6), ph::make (7, 5, 4)));
+  ASSERT_FALSE (known_ge (ch::make (6), ph::make (7, 0, 0)));
+  ASSERT_EQ (known_ge (ch::make (60), ph::make (60, 1, 2)), N == 1);
+  ASSERT_EQ (known_ge (ch::make (60), ph::make (60, 0, 2)), N <= 2);
+  ASSERT_TRUE (known_ge (ch::make (60), ph::make (60, 0, 0)));
+  ASSERT_EQ (known_ge (ch::make (31), ph::make (30, 9, 4)), N == 1);
+  ASSERT_EQ (known_ge (ch::make (31), ph::make (30, 0, 4)), N <= 2);
+  ASSERT_TRUE (known_ge (ch::make (31), ph::make (30, 0, 0)));
+
+  /* Test known_ge (T, T).  */
+  ASSERT_EQ (known_ge (ph::make (3, 14, 99), ph::make (2, 15, 100)), N == 1);
+  ASSERT_EQ (known_ge (ph::make (3, 14, 99), ph::make (2, 13, 100)), N <= 2);
+  ASSERT_EQ (known_ge (ph::make (3, 14, 99), ph::make (2, 15, 98)), N == 1);
+  ASSERT_TRUE (known_ge (ph::make (3, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_TRUE (known_ge (ph::make (3, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_EQ (known_ge (ph::make (2, 14, 99), ph::make (2, 15, 100)), N == 1);
+  ASSERT_EQ (known_ge (ph::make (2, 14, 99), ph::make (2, 13, 100)), N <= 2);
+  ASSERT_EQ (known_ge (ph::make (2, 14, 99), ph::make (2, 15, 98)), N == 1);
+  ASSERT_TRUE (known_ge (ph::make (2, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_TRUE (known_ge (ph::make (2, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_FALSE (known_ge (ph::make (1, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_FALSE (known_ge (ph::make (1, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_FALSE (known_ge (ph::make (1, 14, 99), ph::make (2, 13, 98)));
+}
+
+/* Test known_lt for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_known_lt ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_lt (T, C).  */
+  ASSERT_FALSE (known_lt (ph::make (7, 5, 4), ch::make (6)));
+  ASSERT_FALSE (known_lt (ph::make (7, 0, 0), ch::make (6)));
+  ASSERT_FALSE (known_lt (ph::make (60, 1, 2), ch::make (60)));
+  ASSERT_FALSE (known_lt (ph::make (60, 0, 0), ch::make (60)));
+  ASSERT_EQ (known_lt (ph::make (30, 9, 4), ch::make (31)), N == 1);
+  ASSERT_EQ (known_lt (ph::make (30, 0, 4), ch::make (31)), N <= 2);
+  ASSERT_TRUE (known_lt (ph::make (30, 0, 0), ch::make (31)));
+
+  /* Test known_lt (C, T).  */
+  ASSERT_TRUE (known_lt (ch::make (6), ph::make (7, 5, 4)));
+  ASSERT_TRUE (known_lt (ch::make (6), ph::make (7, 0, 0)));
+  ASSERT_FALSE (known_lt (ch::make (60), ph::make (60, 1, 2)));
+  ASSERT_FALSE (known_lt (ch::make (60), ph::make (60, 0, 0)));
+  ASSERT_FALSE (known_lt (ch::make (31), ph::make (30, 9, 4)));
+  ASSERT_FALSE (known_lt (ch::make (31), ph::make (30, 0, 0)));
+
+  /* Test known_lt (T, T).  */
+  ASSERT_FALSE (known_lt (ph::make (3, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_FALSE (known_lt (ph::make (3, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_FALSE (known_lt (ph::make (3, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_FALSE (known_lt (ph::make (2, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_FALSE (known_lt (ph::make (2, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_FALSE (known_lt (ph::make (2, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_TRUE (known_lt (ph::make (1, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_TRUE (known_lt (ph::make (1, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_EQ (known_lt (ph::make (1, 14, 99), ph::make (2, 15, 98)), N <= 2);
+  ASSERT_EQ (known_lt (ph::make (1, 14, 99), ph::make (2, 13, 100)), N == 1);
+  ASSERT_EQ (known_lt (ph::make (1, 14, 99), ph::make (2, 13, 98)), N == 1);
+}
+
+/* Test known_le for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_known_le ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_le (T, C).  */
+  ASSERT_FALSE (known_le (ph::make (7, 5, 4), ch::make (6)));
+  ASSERT_FALSE (known_le (ph::make (7, 0, 0), ch::make (6)));
+  ASSERT_EQ (known_le (ph::make (60, 1, 2), ch::make (60)), N == 1);
+  ASSERT_EQ (known_le (ph::make (60, 0, 2), ch::make (60)), N <= 2);
+  ASSERT_TRUE (known_le (ph::make (60, 0, 0), ch::make (60)));
+  ASSERT_EQ (known_le (ph::make (30, 9, 4), ch::make (31)), N == 1);
+  ASSERT_EQ (known_le (ph::make (30, 0, 4), ch::make (31)), N <= 2);
+  ASSERT_TRUE (known_le (ph::make (30, 0, 0), ch::make (31)));
+
+  /* Test known_le (C, T).  */
+  ASSERT_TRUE (known_le (ch::make (6), ph::make (7, 5, 4)));
+  ASSERT_TRUE (known_le (ch::make (6), ph::make (7, 0, 0)));
+  ASSERT_TRUE (known_le (ch::make (60), ph::make (60, 1, 2)));
+  ASSERT_TRUE (known_le (ch::make (60), ph::make (60, 0, 0)));
+  ASSERT_FALSE (known_le (ch::make (31), ph::make (30, 9, 4)));
+  ASSERT_FALSE (known_le (ch::make (31), ph::make (30, 0, 0)));
+
+  /* Test known_le (T, T).  */
+  ASSERT_FALSE (known_le (ph::make (3, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_FALSE (known_le (ph::make (3, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_FALSE (known_le (ph::make (3, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_TRUE (known_le (ph::make (2, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_TRUE (known_le (ph::make (2, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_EQ (known_le (ph::make (2, 14, 99), ph::make (2, 15, 98)), N <= 2);
+  ASSERT_EQ (known_le (ph::make (2, 14, 99), ph::make (2, 13, 100)), N == 1);
+  ASSERT_EQ (known_le (ph::make (2, 14, 99), ph::make (2, 13, 98)), N == 1);
+  ASSERT_TRUE (known_le (ph::make (1, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_TRUE (known_le (ph::make (1, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_EQ (known_le (ph::make (1, 14, 99), ph::make (2, 15, 98)), N <= 2);
+  ASSERT_EQ (known_le (ph::make (1, 14, 99), ph::make (2, 13, 100)), N == 1);
+  ASSERT_EQ (known_le (ph::make (1, 14, 99), ph::make (2, 13, 98)), N == 1);
+}
+
+/* Test ordered_p for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_ordered_p ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test ordered_p (T, C).  */
+  ASSERT_EQ (ordered_p (ph::make (4, 1, 2), ch::make (5)), N == 1);
+  ASSERT_EQ (ordered_p (ph::make (4, 0, 2), ch::make (5)), N <= 2);
+  ASSERT_TRUE (ordered_p (ph::make (4, 0, 0), ch::make (5)));
+  ASSERT_TRUE (ordered_p (ph::make (4, 1, 2), ch::make (4)));
+  ASSERT_TRUE (ordered_p (ph::make (4, 0, 0), ch::make (4)));
+  ASSERT_TRUE (ordered_p (ph::make (4, 1, 2), ch::make (3)));
+  ASSERT_TRUE (ordered_p (ph::make (4, 0, 0), ch::make (3)));
+  ASSERT_TRUE (ordered_p (ph::make (4, 4, 4), ch::make (0)));
+  ASSERT_TRUE (ordered_p (ph::make (4, 4, 0), ch::make (0)));
+  ASSERT_TRUE (ordered_p (ph::make (4, 0, 4), ch::make (0)));
+  ASSERT_TRUE (ordered_p (ph::make (-4, -4, -4), ch::make (0)));
+  ASSERT_TRUE (ordered_p (ph::make (-4, -4, 0), ch::make (0)));
+  ASSERT_TRUE (ordered_p (ph::make (-4, 0, -4), ch::make (0)));
+
+  /* Test ordered_p (C, T).  */
+  ASSERT_EQ (ordered_p (ch::make (5), ph::make (4, 1, 2)), N == 1);
+  ASSERT_EQ (ordered_p (ch::make (5), ph::make (4, 0, 2)), N <= 2);
+  ASSERT_TRUE (ordered_p (ch::make (5), ph::make (4, 0, 0)));
+  ASSERT_TRUE (ordered_p (ch::make (4), ph::make (4, 1, 2)));
+  ASSERT_TRUE (ordered_p (ch::make (4), ph::make (4, 0, 0)));
+  ASSERT_TRUE (ordered_p (ch::make (3), ph::make (4, 1, 2)));
+  ASSERT_TRUE (ordered_p (ch::make (3), ph::make (4, 0, 0)));
+  ASSERT_TRUE (ordered_p (ch::make (0), ph::make (4, 4, 4)));
+  ASSERT_TRUE (ordered_p (ch::make (0), ph::make (4, 4, 0)));
+  ASSERT_TRUE (ordered_p (ch::make (0), ph::make (4, 0, 4)));
+  ASSERT_TRUE (ordered_p (ch::make (0), ph::make (-4, -4, -4)));
+  ASSERT_TRUE (ordered_p (ch::make (0), ph::make (-4, -4, 0)));
+  ASSERT_TRUE (ordered_p (ch::make (0), ph::make (-4, 0, -4)));
+
+  /* Test ordered_p (T, T).  */
+  ASSERT_EQ (ordered_p (ph::make (3, 14, 99), ph::make (2, 15, 100)), N == 1);
+  ASSERT_EQ (ordered_p (ph::make (3, 14, 99), ph::make (2, 13, 100)), N <= 2);
+  ASSERT_EQ (ordered_p (ph::make (3, 14, 99), ph::make (2, 15, 98)), N == 1);
+  ASSERT_TRUE (ordered_p (ph::make (3, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_TRUE (ordered_p (ph::make (3, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_TRUE (ordered_p (ph::make (2, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_TRUE (ordered_p (ph::make (2, 14, 99), ph::make (2, 14, 100)));
+  ASSERT_TRUE (ordered_p (ph::make (2, 14, 99), ph::make (2, 15, 99)));
+  ASSERT_EQ (ordered_p (ph::make (2, 14, 99), ph::make (2, 13, 100)), N <= 2);
+  ASSERT_TRUE (ordered_p (ph::make (2, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_EQ (ordered_p (ph::make (2, 14, 99), ph::make (2, 15, 98)), N <= 2);
+  ASSERT_TRUE (ordered_p (ph::make (2, 14, 99), ph::make (2, 13, 99)));
+  ASSERT_TRUE (ordered_p (ph::make (2, 14, 99), ph::make (2, 14, 98)));
+  ASSERT_TRUE (ordered_p (ph::make (2, 14, 99), ph::make (2, 13, 98)));
+  ASSERT_TRUE (ordered_p (ph::make (1, 14, 99), ph::make (2, 15, 100)));
+  ASSERT_TRUE (ordered_p (ph::make (1, 14, 99), ph::make (2, 14, 99)));
+  ASSERT_EQ (ordered_p (ph::make (1, 14, 99), ph::make (2, 15, 98)), N <= 2);
+  ASSERT_EQ (ordered_p (ph::make (1, 14, 99), ph::make (2, 13, 100)), N == 1);
+  ASSERT_EQ (ordered_p (ph::make (1, 14, 99), ph::make (2, 13, 98)), N == 1);
+}
+
+/* Test ordered_min for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_ordered_min ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test ordered_min (T, C).  */
+  ASSERT_KNOWN_EQ (ordered_min (ph::make (4, 0, 0), ch::make (5)),
+                  ch::make (4));
+  ASSERT_KNOWN_EQ (ordered_min (ph::make (12, 0, 0), ch::make (11)),
+                  ch::make (11));
+  ASSERT_KNOWN_EQ (ordered_min (ph::make (12, 6, 4), ch::make (11)),
+                  ch::make (11));
+
+  /* Test ordered_min (C, T).  */
+  ASSERT_KNOWN_EQ (ordered_min (ch::make (5), ph::make (4, 0, 0)),
+                  ch::make (4));
+  ASSERT_KNOWN_EQ (ordered_min (ch::make (11), ph::make (12, 0, 0)),
+                  ch::make (11));
+  ASSERT_KNOWN_EQ (ordered_min (ch::make (11), ph::make (12, 6, 4)),
+                  ch::make (11));
+
+  /* Test ordered_min (T, T).  */
+  ASSERT_KNOWN_EQ (ordered_min (ph::make (4, 6, 14), ph::make (5, 6, 19)),
+                  ph::make (4, 6, 14));
+  ASSERT_KNOWN_EQ (ordered_min (ph::make (4, 9, 17), ph::make (3, 9, 0)),
+                  ph::make (3, 9, 0));
+  ASSERT_KNOWN_EQ (ordered_min (ph::make (-4, -5, 12), ph::make (-3, -5, 12)),
+                  ph::make (-4, -5, 12));
+  ASSERT_KNOWN_EQ (ordered_min (ph::make (4, -9, 6), ph::make (4, -8, 6)),
+                  ph::make (4, -9, 6));
+  ASSERT_KNOWN_EQ (ordered_min (ph::make (5, -1, -14), ph::make (5, -1, -16)),
+                  ph::make (5, -1, -16));
+}
+
+/* Test ordered_max for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_ordered_max ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test ordered_max (T, C).  */
+  ASSERT_KNOWN_EQ (ordered_max (ph::make (4, 0, 0), ch::make (5)),
+                  ch::make (5));
+  ASSERT_KNOWN_EQ (ordered_max (ph::make (12, 0, 0), ch::make (11)),
+                  ch::make (12));
+  ASSERT_KNOWN_EQ (ordered_max (ph::make (12, 6, 4), ch::make (11)),
+                  ph::make (12, 6, 4));
+
+  /* Test ordered_max (C, T).  */
+  ASSERT_KNOWN_EQ (ordered_max (ch::make (5), ph::make (4, 0, 0)),
+                  ch::make (5));
+  ASSERT_KNOWN_EQ (ordered_max (ch::make (11), ph::make (12, 0, 0)),
+                  ch::make (12));
+  ASSERT_KNOWN_EQ (ordered_max (ch::make (11), ph::make (12, 6, 4)),
+                  ph::make (12, 6, 4));
+
+  /* Test ordered_max (T, T).  */
+  ASSERT_KNOWN_EQ (ordered_max (ph::make (4, 6, 14), ph::make (5, 6, 19)),
+                  ph::make (5, 6, 19));
+  ASSERT_KNOWN_EQ (ordered_max (ph::make (4, 9, 17), ph::make (3, 9, 0)),
+                  ph::make (4, 9, 17));
+  ASSERT_KNOWN_EQ (ordered_max (ph::make (-4, -5, 12), ph::make (-3, -5, 12)),
+                  ph::make (-3, -5, 12));
+  ASSERT_KNOWN_EQ (ordered_max (ph::make (4, -9, 6), ph::make (4, -8, 6)),
+                  ph::make (4, -8, 6));
+  ASSERT_KNOWN_EQ (ordered_max (ph::make (5, -1, -14), ph::make (5, -1, -16)),
+                  ph::make (5, -1, -14));
+}
+
+/* Test constant_lower_bound for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_constant_lower_bound ()
+{
+  typedef poly_helper<T> ph;
+
+  ASSERT_EQ (constant_lower_bound (ph::make (4, 1, 2)), 4);
+  ASSERT_EQ (constant_lower_bound (ph::make (5, 0, 1)), 5);
+  ASSERT_EQ (constant_lower_bound (ph::make (6, 1, 0)), 6);
+  ASSERT_EQ (constant_lower_bound (ph::make (7, 0, 0)), 7);
+}
+
+/* Test lower_bound for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_lower_bound ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test lower_bound (T, C).  */
+  ASSERT_KNOWN_EQ (lower_bound (ph::make (7, 2, 15), ch::make (4)),
+                  ch::make (4));
+  ASSERT_KNOWN_EQ (lower_bound (ph::make (100, 5, 50), ch::make (200)),
+                  ch::make (100));
+
+  /* Test lower_bound (C, T).  */
+  ASSERT_KNOWN_EQ (lower_bound (ch::make (4), ph::make (7, 2, 15)),
+                  ch::make (4));
+  ASSERT_KNOWN_EQ (lower_bound (ch::make (200), ph::make (100, 5, 50)),
+                  ch::make (100));
+
+  /* Test lower_bound (T, T).  */
+  ASSERT_KNOWN_EQ (lower_bound (ph::make (7, 2, 15), ph::make (5, 19, 14)),
+                  ph::make (5, 2, 14));
+  ASSERT_KNOWN_EQ (lower_bound (ph::make (100, 5, 50), ph::make (200, 0, 80)),
+                  ph::make (100, 0, 50));
+}
+
+/* Test upper_bound for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_upper_bound ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test upper_bound (T, C).  */
+  ASSERT_KNOWN_EQ (upper_bound (ph::make (7, 2, 15), ch::make (4)),
+                  ph::make (7, 2, 15));
+  ASSERT_KNOWN_EQ (upper_bound (ph::make (100, 5, 50), ch::make (200)),
+                  ph::make (200, 5, 50));
+
+  /* Test upper_bound (C, T).  */
+  ASSERT_KNOWN_EQ (upper_bound (ch::make (4), ph::make (7, 2, 15)),
+                  ph::make (7, 2, 15));
+  ASSERT_KNOWN_EQ (upper_bound (ch::make (200), ph::make (100, 5, 50)),
+                  ph::make (200, 5, 50));
+
+  /* Test upper_bound (T, T).  */
+  ASSERT_KNOWN_EQ (upper_bound (ph::make (7, 2, 15), ph::make (5, 19, 14)),
+                  ph::make (7, 19, 15));
+  ASSERT_KNOWN_EQ (upper_bound (ph::make (100, 5, 50), ph::make (200, 0, 80)),
+                  ph::make (200, 5, 80));
+}
+
+/* Test compare_sizes_for_sort for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_compare_sizes_for_sort ()
+{
+  typedef poly_helper<T> ph;
+
+  ASSERT_EQ (compare_sizes_for_sort (ph::make (5, 10, 8),
+                                    ph::make (7, 9, 11)),
+            N == 2 ? 1 : -1);
+  ASSERT_EQ (compare_sizes_for_sort (ph::make (5, 9, 8),
+                                    ph::make (7, 9, 11)),
+            -1);
+  ASSERT_EQ (compare_sizes_for_sort (ph::make (19, 9, 13),
+                                    ph::make (7, 9, 13)),
+            1);
+  ASSERT_EQ (compare_sizes_for_sort (ph::make (5, 9, 7),
+                                    ph::make (5, 10, 5)),
+            N == 1 ? 0 : N == 2 ? -1 : 1);
+  ASSERT_EQ (compare_sizes_for_sort (ph::make (10, 9, 10),
+                                    ph::make (10, 9, 6)),
+            N <= 2 ? 0 : 1);
+  ASSERT_EQ (compare_sizes_for_sort (ph::make (10, 9, 6),
+                                    ph::make (10, 9, 6)),
+            0);
+}
+
+/* Test force_align_up_and_div for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_force_align_up_and_div ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  ASSERT_KNOWN_EQ (force_align_up_and_div (ph::make (41, 32, 16), 16),
+                  ph::make (3, 2, 1));
+  ASSERT_KNOWN_EQ (force_align_up_and_div (ph::make (-39, -64, -32), 32),
+                  ph::make (C (-32) / 32, C (-64) / 32, C (-32) / 32));
+  ASSERT_KNOWN_EQ (force_align_up_and_div (ph::make (17, 0, 0), 16),
+                  ch::make (2));
+  ASSERT_KNOWN_EQ (force_align_up_and_div (ph::make (16, 0, 0), 16),
+                  ch::make (1));
+  ASSERT_KNOWN_EQ (force_align_up_and_div (ph::make (15, 0, 0), 16),
+                  ch::make (1));
+  ASSERT_KNOWN_EQ (force_align_up_and_div (ph::make (-17, 0, 0), 16),
+                  ch::make (C (-16) / 16));
+  ASSERT_KNOWN_EQ (force_align_up_and_div (ph::make (-16, 0, 0), 16),
+                  ch::make (C (-16) / 16));
+  /* For unsigned short C this gives 0x10000 / 16.  */
+  ASSERT_KNOWN_EQ (force_align_up_and_div (ph::make (-15, 0, 0), 16),
+                  ch::make ((C (-1) + 1) / 16));
+}
+
+/* Test force_align_down_and_div for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_force_align_down_and_div ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  ASSERT_KNOWN_EQ (force_align_down_and_div (ph::make (41, 32, 16), 16),
+                  ph::make (2, 2, 1));
+  ASSERT_KNOWN_EQ (force_align_down_and_div (ph::make (-39, -64, -32), 32),
+                  ph::make (C (-64) / 32, C (-64) / 32, C (-32) / 32));
+  ASSERT_KNOWN_EQ (force_align_down_and_div (ph::make (17, 0, 0), 16),
+                  ch::make (1));
+  ASSERT_KNOWN_EQ (force_align_down_and_div (ph::make (16, 0, 0), 16),
+                  ch::make (1));
+  ASSERT_KNOWN_EQ (force_align_down_and_div (ph::make (15, 0, 0), 16),
+                  ch::make (0));
+  ASSERT_KNOWN_EQ (force_align_down_and_div (ph::make (-17, 0, 0), 16),
+                  ch::make (C (-32) / 16));
+  ASSERT_KNOWN_EQ (force_align_down_and_div (ph::make (-16, 0, 0), 16),
+                  ch::make (C (-16) / 16));
+  ASSERT_KNOWN_EQ (force_align_down_and_div (ph::make (-15, 0, 0), 16),
+                  ch::make (C (-16) / 16));
+}
+
+/* Test constant_multiple_p for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_constant_multiple_p ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test constant_multiple_p (T, C).  */
+  C const_multiple;
+  ASSERT_TRUE (constant_multiple_p (ph::make (15, 0, 0), 5,
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, 3);
+  ASSERT_FALSE (constant_multiple_p (ph::make (16, 0, 0), 5,
+                                    &const_multiple));
+  ASSERT_FALSE (constant_multiple_p (ph::make (14, 5, 5), 5,
+                                    &const_multiple));
+  ASSERT_EQ (constant_multiple_p (ph::make (44, 0, 55), 11,
+                                 &const_multiple), N <= 2);
+  ASSERT_EQ (const_multiple, N <= 2 ? 4 : 3);
+  ASSERT_EQ (constant_multiple_p (ph::make (30, 30, 0), 6,
+                                 &const_multiple), N == 1);
+  ASSERT_EQ (const_multiple, N == 1 ? 5 : N == 2 ? 4 : 3);
+  ASSERT_TRUE (constant_multiple_p (ph::make (0, 0, 0), 5,
+                                   &const_multiple));
+
+  /* Test constant_multiple_p (C, T).  */
+  ASSERT_TRUE (constant_multiple_p (15, ph::make (5, 0, 0),
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, 3);
+  ASSERT_FALSE (constant_multiple_p (16, ph::make (5, 0, 0),
+                                    &const_multiple));
+  ASSERT_FALSE (constant_multiple_p (14, ph::make (5, 5, 5),
+                                    &const_multiple));
+  ASSERT_EQ (constant_multiple_p (44, ph::make (11, 0, 4),
+                                 &const_multiple), N <= 2);
+  ASSERT_EQ (const_multiple, N <= 2 ? 4 : 3);
+  ASSERT_EQ (constant_multiple_p (30, ph::make (6, 6, 6),
+                                 &const_multiple), N == 1);
+  ASSERT_EQ (const_multiple, N == 1 ? 5 : N == 2 ? 4 : 3);
+  ASSERT_TRUE (constant_multiple_p (0, ph::make (5, 4, 11),
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, 0);
+
+  /* Test constant_multiple_p (T, T).  */
+  ASSERT_TRUE (constant_multiple_p (ph::make (5, 15, 25),
+                                   ph::make (1, 3, 5),
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, 5);
+  ASSERT_EQ (constant_multiple_p (ph::make (18, 30, 7),
+                                 ph::make (6, 10, 2),
+                                 &const_multiple), N <= 2);
+  ASSERT_EQ (const_multiple, N <= 2 ? 3 : 5);
+  ASSERT_EQ (constant_multiple_p (ph::make (54, 19, 0),
+                                 ph::make (9, 3, 0),
+                                 &const_multiple), N == 1);
+  ASSERT_EQ (const_multiple, N == 1 ? 6 : N == 2 ? 3: 5);
+  ASSERT_TRUE (constant_multiple_p (ph::make (120, 0, 90),
+                                   ph::make (12, 0, 9),
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, 10);
+  ASSERT_EQ (constant_multiple_p (ph::make (110, 1, 22),
+                                 ph::make (10, 0, 2),
+                                 &const_multiple), N == 1);
+  ASSERT_EQ (const_multiple, N == 1 ? 11 : 10);
+  ASSERT_EQ (constant_multiple_p (ph::make (120, -1, 22),
+                                 ph::make (10, 0, 2),
+                                 &const_multiple), N == 1);
+  ASSERT_EQ (const_multiple, N == 1 ? 12 : 10);
+  ASSERT_EQ (constant_multiple_p (ph::make (130, 0, 26),
+                                 ph::make (10, 1, 2),
+                                 &const_multiple), N == 1);
+  ASSERT_EQ (const_multiple, N == 1 ? 13 : 10);
+  ASSERT_EQ (constant_multiple_p (ph::make (140, 0, 28),
+                                 ph::make (10, -1, 2),
+                                 &const_multiple), N == 1);
+  ASSERT_EQ (const_multiple, N == 1 ? 14 : 10);
+  ASSERT_FALSE (constant_multiple_p (ph::make (89, 0, 0),
+                                    ph::make (11, 0, 0),
+                                    &const_multiple));
+  ASSERT_TRUE (constant_multiple_p (ph::make (88, 0, 0),
+                                   ph::make (11, 0, 0),
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, 8);
+  ASSERT_FALSE (constant_multiple_p (ph::make (87, 0, 0),
+                                    ph::make (11, 0, 0),
+                                    &const_multiple));
+  ASSERT_TRUE (constant_multiple_p (ph::make (35, 63, 0),
+                                   ph::make (5, 9, 0),
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, 7);
+  ASSERT_TRUE (constant_multiple_p (ph::make (0, 0, 0),
+                                   ph::make (11, -24, 25),
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, 0);
+}
+
+/* Test multiple_p for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_multiple_p ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test multiple_p (T, C).  */
+  ASSERT_TRUE (multiple_p (ph::make (15, 0, 0), 5));
+  ASSERT_FALSE (multiple_p (ph::make (16, 0, 0), 5));
+  ASSERT_FALSE (multiple_p (ph::make (14, 5, 5), 5));
+  ASSERT_TRUE (multiple_p (ph::make (44, 0, 55), 11));
+  ASSERT_TRUE (multiple_p (ph::make (30, 30, 0), 6));
+  ASSERT_TRUE (multiple_p (ph::make (30, 35, 45), 5));
+  ASSERT_EQ (multiple_p (ph::make (30, 35, 44), 5), N <= 2);
+  ASSERT_EQ (multiple_p (ph::make (30, 34, 45), 5), N == 1);
+  ASSERT_TRUE (multiple_p (ph::make (0, 0, 0), 5));
+
+  /* Test multiple_p (C, T).  */
+  ASSERT_TRUE (multiple_p (15, ph::make (5, 0, 0)));
+  ASSERT_FALSE (multiple_p (16, ph::make (5, 0, 0)));
+  ASSERT_FALSE (multiple_p (14, ph::make (5, 5, 5)));
+  ASSERT_EQ (multiple_p (44, ph::make (11, 0, 4)), N <= 2);
+  ASSERT_EQ (multiple_p (30, ph::make (6, 6, 6)), N == 1);
+  ASSERT_TRUE (multiple_p (0, ph::make (5, 4, 11)));
+
+  /* Test multiple_p (T, T).  */
+  ASSERT_TRUE (multiple_p (ph::make (15, 0, 0),
+                          ph::make (5, 0, 0)));
+  ASSERT_FALSE (multiple_p (ph::make (16, 0, 0),
+                           ph::make (5, 0, 0)));
+  ASSERT_FALSE (multiple_p (ph::make (14, 5, 5),
+                           ph::make (5, 0, 0)));
+  ASSERT_TRUE (multiple_p (ph::make (44, 0, 55),
+                          ph::make (11, 0, 0)));
+  ASSERT_TRUE (multiple_p (ph::make (30, 30, 0),
+                          ph::make (6, 0, 0)));
+  ASSERT_TRUE (multiple_p (ph::make (30, 35, 45),
+                          ph::make (5, 0, 0)));
+  ASSERT_EQ (multiple_p (ph::make (30, 35, 44),
+                        ph::make (5, 0, 0)), N <= 2);
+  ASSERT_EQ (multiple_p (ph::make (30, 34, 45),
+                        ph::make (5, 0, 0)), N == 1);
+  ASSERT_TRUE (multiple_p (ph::make (0, 0, 0),
+                          ph::make (5, 0, 0)));
+  ASSERT_TRUE (multiple_p (ph::make (15, 0, 0),
+                          ph::make (5, 0, 0)));
+  ASSERT_FALSE (multiple_p (ph::make (16, 0, 0),
+                           ph::make (5, 0, 0)));
+  ASSERT_FALSE (multiple_p (ph::make (14, 0, 0),
+                           ph::make (5, 5, 5)));
+  ASSERT_EQ (multiple_p (ph::make (44, 0, 0),
+                        ph::make (11, 0, 4)), N <= 2);
+  ASSERT_EQ (multiple_p (ph::make (30, 0, 0),
+                        ph::make (6, 6, 6)), N == 1);
+  ASSERT_TRUE (multiple_p (ph::make (0, 0, 0),
+                          ph::make (5, 4, 11)));
+  ASSERT_TRUE (multiple_p (ph::make (5, 15, 25),
+                          ph::make (1, 3, 5)));
+  ASSERT_EQ (multiple_p (ph::make (18, 30, 7),
+                        ph::make (6, 10, 2)), N <= 2);
+  ASSERT_EQ (multiple_p (ph::make (54, 19, 0),
+                        ph::make (9, 3, 0)), N == 1);
+  ASSERT_TRUE (multiple_p (ph::make (120, 0, 90),
+                          ph::make (12, 0, 9)));
+  ASSERT_EQ (multiple_p (ph::make (110, 1, 22),
+                        ph::make (10, 0, 2)), N == 1);
+  ASSERT_EQ (multiple_p (ph::make (120, -1, 22),
+                        ph::make (10, 0, 2)), N == 1);
+  ASSERT_EQ (multiple_p (ph::make (130, 0, 26),
+                        ph::make (10, 1, 2)), N == 1);
+  ASSERT_EQ (multiple_p (ph::make (140, 0, 28),
+                        ph::make (10, -1, 2)), N == 1);
+  ASSERT_FALSE (multiple_p (ph::make (89, 0, 0),
+                           ph::make (11, 0, 0)));
+  ASSERT_TRUE (multiple_p (ph::make (88, 0, 0),
+                          ph::make (11, 0, 0)));
+  ASSERT_FALSE (multiple_p (ph::make (87, 0, 0),
+                           ph::make (11, 0, 0)));
+  ASSERT_TRUE (multiple_p (ph::make (35, 63, 0),
+                          ph::make (5, 9, 0)));
+  ASSERT_TRUE (multiple_p (ph::make (0, 0, 0),
+                          ph::make (11, -24, 25)));
+}
+
+/* Test the 3-operand form of multiple_p for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_multiple_p_with_result ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test multiple_p (T, C) -> T.  */
+  T multiple;
+  ASSERT_TRUE (multiple_p (ph::make (15, 0, 0), 5, &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (3));
+  ASSERT_FALSE (multiple_p (ph::make (16, 0, 0), 5, &multiple));
+  ASSERT_FALSE (multiple_p (ph::make (14, 5, 5), 5, &multiple));
+  ASSERT_TRUE (multiple_p (ph::make (44, 0, 55), 11, &multiple));
+  ASSERT_KNOWN_EQ (multiple, ph::make (4, 0, 5));
+  ASSERT_TRUE (multiple_p (ph::make (30, 30, 0), 6, &multiple));
+  ASSERT_KNOWN_EQ (multiple, ph::make (5, 5, 0));
+  ASSERT_TRUE (multiple_p (ph::make (30, 35, 45), 5, &multiple));
+  ASSERT_KNOWN_EQ (multiple, ph::make (6, 7, 9));
+  ASSERT_EQ (multiple_p (ph::make (30, 35, 44), 5, &multiple), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (multiple, ph::make (6, 7, 0));
+  ASSERT_EQ (multiple_p (ph::make (30, 34, 45), 5, &multiple), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (multiple, ch::make (6));
+  ASSERT_TRUE (multiple_p (ph::make (0, 0, 0), 5, &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (0));
+
+  /* Test multiple_p (C, T) -> T.  */
+  ASSERT_TRUE (multiple_p (15, ph::make (5, 0, 0), &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (3));
+  ASSERT_FALSE (multiple_p (16, ph::make (5, 0, 0), &multiple));
+  ASSERT_FALSE (multiple_p (14, ph::make (5, 5, 5), &multiple));
+  ASSERT_EQ (multiple_p (44, ph::make (11, 0, 4), &multiple), N <= 2);
+  ASSERT_KNOWN_EQ (multiple, ch::make (N <= 2 ? 4 : 3));
+  ASSERT_EQ (multiple_p (30, ph::make (6, 6, 6), &multiple), N == 1);
+  ASSERT_KNOWN_EQ (multiple, ch::make (N == 1 ? 5 : N == 2 ? 4 : 3));
+  ASSERT_TRUE (multiple_p (0, ph::make (5, 4, 11), &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (0));
+
+  /* Test multiple_p (T, T) -> T.  */
+  ASSERT_TRUE (multiple_p (ph::make (15, 0, 0),
+                          ph::make (5, 0, 0),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (3));
+  ASSERT_FALSE (multiple_p (ph::make (16, 0, 0),
+                           ph::make (5, 0, 0),
+                           &multiple));
+  ASSERT_FALSE (multiple_p (ph::make (14, 5, 5),
+                           ph::make (5, 0, 0),
+                           &multiple));
+  ASSERT_TRUE (multiple_p (ph::make (44, 0, 55),
+                          ph::make (11, 0, 0),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ph::make (4, 0, 5));
+  ASSERT_TRUE (multiple_p (ph::make (30, 30, 0),
+                          ph::make (6, 0, 0),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ph::make (5, 5, 0));
+  ASSERT_TRUE (multiple_p (ph::make (30, 35, 45),
+                          ph::make (5, 0, 0),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ph::make (6, 7, 9));
+  ASSERT_EQ (multiple_p (ph::make (30, 35, 44),
+                        ph::make (5, 0, 0),
+                        &multiple), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (multiple, ph::make (6, 7, 0));
+  ASSERT_EQ (multiple_p (ph::make (30, 34, 45),
+                        ph::make (5, 0, 0),
+                        &multiple), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (multiple, ch::make (6));
+  ASSERT_TRUE (multiple_p (ph::make (0, 0, 0),
+                          ph::make (5, 0, 0),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (0));
+  ASSERT_TRUE (multiple_p (ph::make (15, 0, 0),
+                          ph::make (5, 0, 0),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (3));
+  ASSERT_FALSE (multiple_p (ph::make (16, 0, 0),
+                           ph::make (5, 0, 0),
+                           &multiple));
+  ASSERT_FALSE (multiple_p (ph::make (14, 0, 0),
+                           ph::make (5, 5, 5),
+                           &multiple));
+  ASSERT_EQ (multiple_p (ph::make (44, 0, 0),
+                        ph::make (11, 0, 4),
+                        &multiple), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (multiple, ch::make (4));
+  ASSERT_EQ (multiple_p (ph::make (30, 0, 0),
+                        ph::make (6, 6, 6),
+                        &multiple), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (multiple, ch::make (5));
+  ASSERT_TRUE (multiple_p (ph::make (0, 0, 0),
+                          ph::make (5, 4, 11),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (0));
+  ASSERT_TRUE (multiple_p (ph::make (5, 15, 25),
+                          ph::make (1, 3, 5),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (5));
+  ASSERT_EQ (multiple_p (ph::make (18, 30, 7),
+                        ph::make (6, 10, 2),
+                        &multiple), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (multiple, ch::make (3));
+  ASSERT_EQ (multiple_p (ph::make (54, 19, 0),
+                        ph::make (9, 3, 0),
+                        &multiple), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (multiple, ch::make (6));
+  ASSERT_TRUE (multiple_p (ph::make (120, 0, 90),
+                          ph::make (12, 0, 9),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (10));
+  ASSERT_EQ (multiple_p (ph::make (110, 1, 22),
+                        ph::make (10, 0, 2),
+                        &multiple), N == 1);
+  ASSERT_KNOWN_EQ (multiple, ch::make (N == 1 ? 11 : 10));
+  ASSERT_EQ (multiple_p (ph::make (120, -1, 22),
+                        ph::make (10, 0, 2),
+                        &multiple), N == 1);
+  ASSERT_KNOWN_EQ (multiple, ch::make (N == 1 ? 12 : 10));
+  ASSERT_EQ (multiple_p (ph::make (130, 0, 26),
+                        ph::make (10, 1, 2),
+                        &multiple), N == 1);
+  ASSERT_KNOWN_EQ (multiple, ch::make (N == 1 ? 13 : 10));
+  ASSERT_EQ (multiple_p (ph::make (140, 0, 28),
+                        ph::make (10, -1, 2),
+                        &multiple), N == 1);
+  ASSERT_KNOWN_EQ (multiple, ch::make (N == 1 ? 14 : 10));
+  ASSERT_FALSE (multiple_p (ph::make (89, 0, 0),
+                           ph::make (11, 0, 0),
+                           &multiple));
+  ASSERT_TRUE (multiple_p (ph::make (88, 0, 0),
+                          ph::make (11, 0, 0),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (8));
+  ASSERT_FALSE (multiple_p (ph::make (87, 0, 0),
+                           ph::make (11, 0, 0),
+                           &multiple));
+  ASSERT_TRUE (multiple_p (ph::make (35, 63, 0),
+                          ph::make (5, 9, 0),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (7));
+  ASSERT_TRUE (multiple_p (ph::make (0, 0, 0),
+                          ph::make (11, -24, 25),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (0));
+}
+
+/* Test exact_div for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_exact_div ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test exact_div (T, C).  */
+  ASSERT_KNOWN_EQ (exact_div (ph::make (15, 0, 0), 5),
+                  ch::make (3));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (44, 0, 55), 11),
+                  ph::make (4, 0, 5));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (30, 30, 0), 6),
+                  ph::make (5, 5, 0));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (30, 35, 45), 5),
+                  ph::make (6, 7, 9));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (0, 0, 0), 5),
+                  ch::make (0));
+
+  /* Test exact_div (T, T).  */
+  ASSERT_KNOWN_EQ (exact_div (ph::make (15, 0, 0),
+                             ph::make (5, 0, 0)),
+                  ch::make (3));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (44, 0, 55),
+                             ph::make (11, 0, 0)),
+                  ph::make (4, 0, 5));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (30, 30, 0),
+                             ph::make (6, 0, 0)),
+                  ph::make (5, 5, 0));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (30, 35, 45),
+                             ph::make (5, 0, 0)),
+                  ph::make (6, 7, 9));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (0, 0, 0),
+                             ph::make (5, 0, 0)),
+                  ch::make (0));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (15, 0, 0),
+                             ph::make (5, 0, 0)),
+                  ch::make (3));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (0, 0, 0),
+                             ph::make (5, 4, 11)),
+                  ch::make (0));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (5, 15, 25),
+                             ph::make (1, 3, 5)),
+                  ch::make (5));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (120, 0, 90),
+                             ph::make (12, 0, 9)),
+                  ch::make (10));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (88, 0, 0),
+                             ph::make (11, 0, 0)),
+                  ch::make (8));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (35, 63, 0),
+                             ph::make (5, 9, 0)),
+                  ch::make (7));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (0, 0, 0),
+                             ph::make (11, -24, 25)),
+                  ch::make (0));
+}
+
+/* Test the form of can_div_trunc_p that returns a constant quotient,
+   for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_can_div_trunc_p_const ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test can_div_trunc_p (T, C) -> C.  */
+  C const_quot;
+  ASSERT_TRUE (can_div_trunc_p (ph::make (22, 0, 0), 5, &const_quot));
+  ASSERT_KNOWN_EQ (const_quot, C (4));
+  ASSERT_EQ (can_div_trunc_p (ph::make (44, 0, 1), 5, &const_quot), N <= 2);
+  ASSERT_KNOWN_EQ (const_quot, C (N <= 2 ? 8 : 4));
+  ASSERT_EQ (can_div_trunc_p (ph::make (88, 1, 0), 5, &const_quot), N == 1);
+  ASSERT_KNOWN_EQ (const_quot, C (N == 1 ? 17 : N == 2 ? 8 : 4));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (20, 0, 0), 5, &const_quot));
+  ASSERT_KNOWN_EQ (const_quot, C (4));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (19, 0, 0), 5, &const_quot));
+  ASSERT_KNOWN_EQ (const_quot, C (3));
+
+  /* Test can_div_trunc_p (T, T) -> C.  */
+  ASSERT_TRUE (can_div_trunc_p (ph::make (8, 44, 28),
+                               ph::make (2, 11, 7),
+                               &const_quot));
+  ASSERT_EQ (const_quot, C (4));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (9, 23, 30),
+                               ph::make (4, 8, 12),
+                               &const_quot));
+  ASSERT_EQ (const_quot, C (2));
+  ASSERT_EQ (can_div_trunc_p (ph::make (15, 25, 40),
+                             ph::make (4, 8, 10),
+                             &const_quot), N <= 2);
+  ASSERT_EQ (const_quot, C (N <= 2 ? 3 : 2));
+  ASSERT_EQ (can_div_trunc_p (ph::make (43, 79, 80),
+                             ph::make (4, 8, 10),
+                             &const_quot), N == 1);
+  ASSERT_EQ (const_quot, C (N == 1 ? 10 : N == 2 ? 3 : 2));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (3, 4, 5),
+                               ph::make (4, 5, 6),
+                               &const_quot));
+  ASSERT_EQ (const_quot, C (0));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (3, 4, 6),
+                               ph::make (4, 5, 6),
+                               &const_quot));
+  ASSERT_EQ (const_quot, C (0));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (3, 5, 5),
+                               ph::make (4, 5, 6),
+                               &const_quot));
+  ASSERT_EQ (const_quot, C (0));
+  ASSERT_EQ (can_div_trunc_p (ph::make (3, 4, 7),
+                             ph::make (4, 5, 6),
+                             &const_quot), N <= 2);
+  ASSERT_EQ (const_quot, C (0));
+  ASSERT_EQ (can_div_trunc_p (ph::make (3, 6, 0),
+                             ph::make (4, 5, 6),
+                             &const_quot), N == 1);
+  ASSERT_EQ (const_quot, C (0));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (56, 0, 11),
+                               ph::make (11, 0, 2),
+                               &const_quot));
+  ASSERT_EQ (const_quot, C (5));
+  ASSERT_EQ (can_div_trunc_p (ph::make (66, 1, 12),
+                             ph::make (11, 0, 2),
+                             &const_quot), N == 1);
+  ASSERT_EQ (const_quot, C (N == 1 ? 6 : 5));
+  ASSERT_EQ (can_div_trunc_p (ph::make (77, -1, 14),
+                             ph::make (11, 0, 2),
+                             &const_quot), N == 1);
+  ASSERT_EQ (const_quot, C (N == 1 ? 7 : 5));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (89, 0, 0),
+                               ph::make (11, 0, 0),
+                               &const_quot));
+  ASSERT_EQ (const_quot, C (8));
+  ASSERT_EQ (can_div_trunc_p (ph::make (101, 0, 1),
+                             ph::make (11, 0, 0),
+                             &const_quot), N <= 2);
+  ASSERT_EQ (const_quot, C (N <= 2 ? 9 : 8));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (0, 0, 0),
+                               ph::make (4, 5, 6),
+                               &const_quot));
+  ASSERT_EQ (const_quot, C (0));
+
+  /* Test can_div_trunc_p (T, T) -> C, T.  */
+  T rem;
+  ASSERT_TRUE (can_div_trunc_p (ph::make (8, 44, 28),
+                               ph::make (2, 11, 7),
+                               &const_quot, &rem));
+  ASSERT_EQ (const_quot, C (4));
+  ASSERT_KNOWN_EQ (rem, ch::make (0));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (9, 23, 30),
+                               ph::make (4, 8, 12),
+                               &const_quot, &rem));
+  ASSERT_EQ (const_quot, C (2));
+  ASSERT_KNOWN_EQ (rem, ph::make (1, 7, 6));
+  ASSERT_EQ (can_div_trunc_p (ph::make (15, 25, 40),
+                             ph::make (4, 8, 10),
+                             &const_quot, &rem), N <= 2);
+  ASSERT_EQ (const_quot, C (N <= 2 ? 3 : 2));
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (rem, ph::make (3, 1, 0));
+  ASSERT_EQ (can_div_trunc_p (ph::make (43, 79, 80),
+                             ph::make (4, 8, 10),
+                             &const_quot, &rem), N == 1);
+  ASSERT_EQ (const_quot, C (N == 1 ? 10 : N == 2 ? 3 : 2));
+  if (N == 1)
+    ASSERT_KNOWN_EQ (rem, ch::make (3));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (3, 4, 5),
+                               ph::make (4, 5, 6),
+                               &const_quot, &rem));
+  ASSERT_EQ (const_quot, C (0));
+  ASSERT_KNOWN_EQ (rem, ph::make (3, 4, 5));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (3, 4, 6),
+                               ph::make (4, 5, 6),
+                               &const_quot, &rem));
+  ASSERT_EQ (const_quot, C (0));
+  ASSERT_KNOWN_EQ (rem, ph::make (3, 4, 6));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (3, 5, 5),
+                               ph::make (4, 5, 6),
+                               &const_quot, &rem));
+  ASSERT_EQ (const_quot, C (0));
+  ASSERT_KNOWN_EQ (rem, ph::make (3, 5, 5));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (56, 0, 11),
+                               ph::make (11, 0, 2),
+                               &const_quot, &rem));
+  ASSERT_EQ (const_quot, C (5));
+  ASSERT_KNOWN_EQ (rem, ph::make (1, 0, 1));
+  ASSERT_EQ (can_div_trunc_p (ph::make (66, 1, 12),
+                             ph::make (11, 0, 2),
+                             &const_quot, &rem), N == 1);
+  ASSERT_EQ (const_quot, C (N == 1 ? 6 : 5));
+  if (N == 1)
+    ASSERT_KNOWN_EQ (rem, ch::make (0));
+  ASSERT_EQ (can_div_trunc_p (ph::make (77, -1, 14),
+                             ph::make (11, 0, 2),
+                             &const_quot, &rem), N == 1);
+  ASSERT_EQ (const_quot, C (N == 1 ? 7 : 5));
+  if (N == 1)
+    ASSERT_KNOWN_EQ (rem, ch::make (0));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (89, 0, 0),
+                               ph::make (11, 0, 0),
+                               &const_quot, &rem));
+  ASSERT_EQ (const_quot, C (8));
+  ASSERT_KNOWN_EQ (rem, ch::make (1));
+  ASSERT_EQ (can_div_trunc_p (ph::make (101, 0, 1),
+                             ph::make (11, 0, 0),
+                             &const_quot, &rem), N <= 2);
+  ASSERT_EQ (const_quot, C (N <= 2 ? 9 : 8));
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (rem, ch::make (2));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (0, 0, 0),
+                               ph::make (4, 5, 6),
+                               &const_quot, &rem));
+  ASSERT_EQ (const_quot, C (0));
+  ASSERT_KNOWN_EQ (rem, ch::make (0));
+}
+
+/* Test the form of can_div_trunc_p that returns a polynomail quotient,
+   for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_can_div_trunc_p_poly ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test can_div_trunc_p (T, C) -> T.  */
+  T quot;
+  ASSERT_TRUE (can_div_trunc_p (ph::make (22, 0, 0), 5, &quot));
+  ASSERT_KNOWN_EQ (quot, ch::make (4));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (45, 40, 24), 4, &quot));
+  ASSERT_KNOWN_EQ (quot, ph::make (11, 10, 6));
+  ASSERT_EQ (can_div_trunc_p (ph::make (13, 18, 19), 6, &quot), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (quot, ph::make (2, 3, 0));
+  ASSERT_EQ (can_div_trunc_p (ph::make (55, 11, 10), 10, &quot), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (quot, ch::make (5));
+
+  /* Test can_div_trunc_p (T, C) -> T, C.  */
+  C const_rem;
+  ASSERT_TRUE (can_div_trunc_p (ph::make (22, 0, 0), 5,
+                               &quot, &const_rem));
+  ASSERT_KNOWN_EQ (quot, ch::make (4));
+  ASSERT_EQ (const_rem, C (2));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (45, 40, 24), 4,
+                               &quot, &const_rem));
+  ASSERT_KNOWN_EQ (quot, ph::make (11, 10, 6));
+  ASSERT_EQ (const_rem, C (1));
+  ASSERT_EQ (can_div_trunc_p (ph::make (13, 18, 19), 6,
+                             &quot, &const_rem), N <= 2);
+  if (N <= 2)
+    {
+      ASSERT_KNOWN_EQ (quot, ph::make (2, 3, 0));
+      ASSERT_EQ (const_rem, C (1));
+    }
+  ASSERT_EQ (can_div_trunc_p (ph::make (55, 11, 10), 10,
+                             &quot, &const_rem), N == 1);
+  if (N == 1)
+    {
+      ASSERT_KNOWN_EQ (quot, ch::make (5));
+      ASSERT_EQ (const_rem, C (5));
+    }
+}
+
+/* Test can_div_away_from_zero_p for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_can_div_away_from_zero_p ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test can_div_away_from_zero_p (T, T) -> C.  */
+  C const_quot;
+  ASSERT_TRUE (can_div_away_from_zero_p (ph::make (8, 44, 28),
+                                        ph::make (2, 11, 7),
+                                        &const_quot));
+  ASSERT_EQ (const_quot, C (4));
+  ASSERT_TRUE (can_div_away_from_zero_p (ph::make (9, 23, 30),
+                                        ph::make (4, 8, 12),
+                                        &const_quot));
+  ASSERT_EQ (const_quot, C (3));
+  ASSERT_EQ (can_div_away_from_zero_p (ph::make (15, 25, 40),
+                                      ph::make (4, 8, 10),
+                                      &const_quot), N <= 2);
+  ASSERT_EQ (const_quot, C (N <= 2 ? 4 : 3));
+  ASSERT_EQ (can_div_away_from_zero_p (ph::make (43, 79, 80),
+                                      ph::make (4, 8, 10),
+                                      &const_quot), N == 1);
+  ASSERT_EQ (const_quot, C (N == 1 ? 11 : N == 2 ? 4 : 3));
+  ASSERT_TRUE (can_div_away_from_zero_p (ph::make (3, 4, 5),
+                                        ph::make (4, 5, 6),
+                                        &const_quot));
+  ASSERT_EQ (const_quot, C (1));
+  ASSERT_TRUE (can_div_away_from_zero_p (ph::make (3, 4, 6),
+                                        ph::make (4, 5, 6),
+                                        &const_quot));
+  ASSERT_EQ (const_quot, C (1));
+  ASSERT_TRUE (can_div_away_from_zero_p (ph::make (3, 5, 5),
+                                        ph::make (4, 5, 6),
+                                        &const_quot));
+  ASSERT_EQ (const_quot, C (1));
+  ASSERT_TRUE (can_div_away_from_zero_p (ph::make (56, 0, 11),
+                                        ph::make (11, 0, 2),
+                                        &const_quot));
+  ASSERT_EQ (const_quot, C (6));
+  ASSERT_EQ (can_div_away_from_zero_p (ph::make (66, 1, 12),
+                                      ph::make (11, 0, 2),
+                                      &const_quot), N == 1);
+  ASSERT_EQ (const_quot, C (6));
+  ASSERT_EQ (can_div_away_from_zero_p (ph::make (77, -1, 14),
+                                      ph::make (11, 0, 2),
+                                      &const_quot), N == 1);
+  ASSERT_EQ (const_quot, C (N == 1 ? 7 : 6));
+  ASSERT_TRUE (can_div_away_from_zero_p (ph::make (89, 0, 0),
+                                        ph::make (11, 0, 0),
+                                        &const_quot));
+  ASSERT_EQ (const_quot, C (9));
+  ASSERT_EQ (can_div_away_from_zero_p (ph::make (101, 0, 1),
+                                      ph::make (11, 0, 0),
+                                      &const_quot), N <= 2);
+  ASSERT_EQ (const_quot, C (N <= 2 ? 10 : 9));
+  ASSERT_TRUE (can_div_away_from_zero_p (ph::make (0, 0, 0),
+                                        ph::make (4, 5, 6),
+                                        &const_quot));
+  ASSERT_EQ (const_quot, C (0));
+}
+
+/* Test known_size_p.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_known_size_p ()
+{
+  typedef poly_helper<T> ph;
+
+  ASSERT_EQ (known_size_p (ph::make (-1, 0, -1)), N == 3);
+  ASSERT_EQ (known_size_p (ph::make (-1, -1, 0)), N >= 2);
+  ASSERT_EQ (known_size_p (ph::make (-1, -1, -1)), N >= 2);
+  ASSERT_FALSE (known_size_p (ph::make (-1, 0, 0)));
+  ASSERT_TRUE (known_size_p (ph::make (0, 0, 0)));
+  ASSERT_TRUE (known_size_p (ph::make (1, 0, 0)));
+}
+
+/* Test maybe_in_range_p for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_maybe_in_range_p ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  ASSERT_FALSE (maybe_in_range_p (ch::make (4),
+                                 ph::make (5, 1, 2),
+                                 ch::make (-1)));
+  ASSERT_FALSE (maybe_in_range_p (ph::make (4, 0, 0),
+                                 ph::make (5, 1, 2),
+                                 ch::make (-1)));
+  ASSERT_FALSE (maybe_in_range_p (ph::make (4, 1, 2),
+                                 ph::make (5, 1, 2),
+                                 ch::make (-1)));
+  ASSERT_TRUE (maybe_in_range_p (ph::make (5, 1, 2),
+                                ph::make (5, 1, 2),
+                                ch::make (-1)));
+  ASSERT_EQ (maybe_in_range_p (ph::make (4, 0, 3),
+                              ph::make (5, 1, 2),
+                              ch::make (-1)), N == 3);
+  ASSERT_EQ (maybe_in_range_p (ph::make (4, 2, 0),
+                              ph::make (5, 1, 2),
+                              ch::make (-1)), N >= 2);
+  ASSERT_TRUE (maybe_in_range_p (ph::make (500, 100, 200),
+                                ph::make (5, 1, 2),
+                                ch::make (-1)));
+  ASSERT_EQ (maybe_in_range_p (ph::make (6, 1, 0),
+                              ph::make (5, 1, 1),
+                              ch::make (1)), N == 3);
+  ASSERT_EQ (maybe_in_range_p (ph::make (6, 0, 1),
+                              ph::make (5, 1, 1),
+                              ch::make (1)), N >= 2);
+  ASSERT_FALSE (maybe_in_range_p (ph::make (14, 1, 2),
+                                 ph::make (5, 1, 2),
+                                 ch::make (9)));
+  ASSERT_FALSE (maybe_in_range_p (ph::make (14, 1, 2),
+                                 ch::make (5),
+                                 ph::make (9, 1, 2)));
+  ASSERT_FALSE (maybe_in_range_p (ph::make (15, 15, 17),
+                                 ph::make (8, 10, 11),
+                                 ph::make (7, 5, 6)));
+  ASSERT_EQ (maybe_in_range_p (ph::make (15, 15, 16),
+                              ph::make (8, 10, 11),
+                              ph::make (7, 5, 6)), N == 3);
+  ASSERT_EQ (maybe_in_range_p (ph::make (15, 14, 17),
+                              ph::make (8, 10, 11),
+                              ph::make (7, 5, 6)), N >= 2);
+  ASSERT_TRUE (maybe_in_range_p (ph::make (6, 100, 1000),
+                                ph::make (5, 10, 11),
+                                ph::make (2, 1, 2)));
+  ASSERT_FALSE (maybe_in_range_p (ph::make (6, 8, 2),
+                                 ph::make (6, 8, 2),
+                                 ch::make (0)));
+  ASSERT_EQ (maybe_in_range_p (ph::make (6, 8, 1),
+                              ph::make (6, 7, 2),
+                              ph::make (0, 1, 2)), N == 3);
+}
+
+/* Test known_in_range_p for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_known_in_range_p ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  ASSERT_FALSE (known_in_range_p (ch::make (4),
+                                 ph::make (5, 1, 2),
+                                 ch::make (-1)));
+  ASSERT_FALSE (known_in_range_p (ph::make (5, 1, 2),
+                                 ph::make (5, 1, 2),
+                                 ch::make (-1)));
+  ASSERT_FALSE (known_in_range_p (ph::make (6, 2, 3),
+                                 ph::make (5, 1, 2),
+                                 ch::make (-1)));
+  ASSERT_FALSE (known_in_range_p (ph::make (6, 1, 0),
+                                 ph::make (5, 1, 1),
+                                 ch::make (1)));
+  ASSERT_FALSE (known_in_range_p (ph::make (6, 0, 1),
+                                 ph::make (5, 1, 1),
+                                 ch::make (1)));
+  ASSERT_EQ (known_in_range_p (ph::make (6, 1, 0),
+                              ph::make (5, 1, 1),
+                              ch::make (2)), N <= 2);
+  ASSERT_EQ (known_in_range_p (ph::make (6, 0, 1),
+                              ph::make (5, 1, 1),
+                              ch::make (2)), N == 1);
+  ASSERT_TRUE (known_in_range_p (ph::make (6, 4, 5),
+                                ph::make (5, 1, 2),
+                                ph::make (2, 3, 3)));
+  ASSERT_EQ (known_in_range_p (ph::make (6, 4, 6),
+                              ph::make (5, 1, 2),
+                              ph::make (2, 3, 3)), N <= 2);
+  ASSERT_EQ (known_in_range_p (ph::make (6, 5, 5),
+                              ph::make (5, 1, 2),
+                              ph::make (2, 3, 3)), N == 1);
+  ASSERT_FALSE (known_in_range_p (ph::make (6, 8, 2),
+                                 ph::make (6, 8, 2),
+                                 ch::make (0)));
+  ASSERT_FALSE (known_in_range_p (ph::make (6, 8, 1),
+                                 ph::make (6, 7, 2),
+                                 ph::make (0, 1, 2)));
+}
+
+/* Test ranges_maybe_overlap_p for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_ranges_maybe_overlap_p ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  ASSERT_TRUE (ranges_maybe_overlap_p (ph::make (4, 1, 2),
+                                      ch::make (-1),
+                                      ph::make (500, 3, 5),
+                                      ch::make (1)));
+  ASSERT_FALSE (ranges_maybe_overlap_p (ph::make (100, 1, 5),
+                                       ch::make (-1),
+                                       ph::make (50, 1, 5),
+                                       ch::make (50)));
+  ASSERT_EQ (ranges_maybe_overlap_p (ph::make (100, 1, 5),
+                                    ch::make (-1),
+                                    ph::make (50, 0, 6),
+                                    ch::make (50)), N == 3);
+  ASSERT_EQ (ranges_maybe_overlap_p (ph::make (100, 1, 5),
+                                    ch::make (-1),
+                                    ph::make (50, 2, 0),
+                                    ch::make (50)), N >= 2);
+  ASSERT_TRUE (ranges_maybe_overlap_p (ph::make (500, 3, 5),
+                                      ch::make (1),
+                                      ph::make (4, 1, 2),
+                                      ch::make (-1)));
+  ASSERT_FALSE (ranges_maybe_overlap_p (ph::make (50, 1, 5),
+                                       ch::make (50),
+                                       ph::make (100, 1, 5),
+                                       ch::make (-1)));
+  ASSERT_FALSE (ranges_maybe_overlap_p (ph::make (10, 2, 3),
+                                       ch::make (0),
+                                       ch::make (0),
+                                       ph::make (20, 30, 40)));
+  ASSERT_EQ (ranges_maybe_overlap_p (ph::make (10, 2, 3),
+                                    ph::make (0, 1, 1),
+                                    ph::make (0, 1, 1),
+                                    ph::make (20, 30, 40)), N >= 2);
+  ASSERT_FALSE (ranges_maybe_overlap_p (ch::make (0),
+                                       ph::make (20, 30, 40),
+                                       ph::make (10, 2, 3),
+                                       ch::make (0)));
+  ASSERT_EQ (ranges_maybe_overlap_p (ph::make (0, 1, 1),
+                                    ph::make (20, 30, 40),
+                                    ph::make (10, 2, 3),
+                                    ph::make (0, 1, 0)), N >= 2);
+  ASSERT_TRUE (ranges_maybe_overlap_p (ph::make (8, 10, 15),
+                                      ph::make (2, 6, 20),
+                                      ch::make (7),
+                                      ch::make (2)));
+  ASSERT_FALSE (ranges_maybe_overlap_p (ph::make (8, 10, 15),
+                                       ph::make (2, 6, 20),
+                                       ch::make (6),
+                                       ph::make (2, 10, 15)));
+  ASSERT_EQ (ranges_maybe_overlap_p (ph::make (8, 10, 15),
+                                    ph::make (2, 6, 20),
+                                    ch::make (6),
+                                    ph::make (0, 0, 16)), N == 3);
+  ASSERT_EQ (ranges_maybe_overlap_p (ph::make (8, 10, 15),
+                                    ph::make (2, 6, 20),
+                                    ch::make (6),
+                                    ph::make (0, 11, 0)), N >= 2);
+  ASSERT_FALSE (ranges_maybe_overlap_p (ph::make (80, 4, 5),
+                                       ph::make (10, 6, 7),
+                                       ph::make (100, 10, 12),
+                                       ph::make (20, 1, 2)));
+  ASSERT_EQ (ranges_maybe_overlap_p (ph::make (80, 4, 5),
+                                    ph::make (10, 6, 7),
+                                    ph::make (100, 10, 11),
+                                    ph::make (0, 0, 2)), N == 3);
+  ASSERT_EQ (ranges_maybe_overlap_p (ph::make (80, 5, 5),
+                                    ph::make (0, 6, 0),
+                                    ph::make (100, 10, 12),
+                                    ph::make (20, 1, 2)), N >= 2);
+}
+
+/* Test ranges_known_overlap_p for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_ranges_known_overlap_p ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  ASSERT_FALSE (ranges_known_overlap_p (ph::make (5, 1, 2),
+                                       ch::make (-1),
+                                       ch::make (4),
+                                       ch::make (2)));
+  ASSERT_FALSE (ranges_known_overlap_p (ch::make (9),
+                                       ph::make (2, 3, 4),
+                                       ch::make (10),
+                                       ch::make (-1)));
+  ASSERT_FALSE (ranges_known_overlap_p (ph::make (10, 2, 3),
+                                       ch::make (0),
+                                       ch::make (0),
+                                       ph::make (20, 30, 40)));
+  ASSERT_FALSE (ranges_known_overlap_p (ph::make (10, 2, 3),
+                                       ph::make (0, 1, 1),
+                                       ph::make (0, 1, 1),
+                                       ph::make (20, 30, 40)));
+  ASSERT_FALSE (ranges_known_overlap_p (ch::make (0),
+                                       ph::make (20, 30, 40),
+                                       ph::make (10, 2, 3),
+                                       ch::make (0)));
+  ASSERT_FALSE (ranges_known_overlap_p (ph::make (0, 1, 1),
+                                       ph::make (20, 30, 40),
+                                       ph::make (10, 2, 3),
+                                       ph::make (0, 1, 0)));
+  ASSERT_EQ (ranges_known_overlap_p (ph::make (5, 1, 2),
+                                    ch::make (1),
+                                    ch::make (4),
+                                    ch::make (2)), N == 1);
+  ASSERT_TRUE (ranges_known_overlap_p (ph::make (5, 1, 2),
+                                      ch::make (1),
+                                      ph::make (4, 1, 2),
+                                      ch::make (2)));
+  ASSERT_TRUE (ranges_known_overlap_p (ch::make (9),
+                                      ph::make (2, 3, 4),
+                                      ch::make (10),
+                                      ch::make (1)));
+  ASSERT_FALSE (ranges_known_overlap_p (ph::make (10, 11, 12),
+                                       ph::make (20, 30, 40),
+                                       ch::make (30),
+                                       ch::make (1)));
+  ASSERT_TRUE (ranges_known_overlap_p (ph::make (10, 11, 12),
+                                      ph::make (20, 30, 40),
+                                      ph::make (29, 41, 52),
+                                      ch::make (1)));
+  ASSERT_EQ (ranges_known_overlap_p (ph::make (10, 11, 12),
+                                    ph::make (20, 30, 40),
+                                    ph::make (29, 41, 53),
+                                    ch::make (1)), N <= 2);
+  ASSERT_EQ (ranges_known_overlap_p (ph::make (10, 11, 12),
+                                    ph::make (20, 30, 40),
+                                    ph::make (29, 42, 52),
+                                    ch::make (1)), N == 1);
+  ASSERT_TRUE (ranges_known_overlap_p (ph::make (29, 41, 52),
+                                      ch::make (1),
+                                      ph::make (10, 11, 12),
+                                      ph::make (20, 30, 40)));
+  ASSERT_EQ (ranges_known_overlap_p (ph::make (29, 41, 53),
+                                    ch::make (1),
+                                    ph::make (10, 11, 12),
+                                    ph::make (20, 30, 40)), N <= 2);
+  ASSERT_EQ (ranges_known_overlap_p (ph::make (29, 42, 52),
+                                    ch::make (1),
+                                    ph::make (10, 11, 12),
+                                    ph::make (20, 30, 40)), N == 1);
+  ASSERT_TRUE (ranges_known_overlap_p (ph::make (10, 0, 20),
+                                      ph::make (4, 4, 4),
+                                      ph::make (7, 3, 20),
+                                      ph::make (4, 4, 4)));
+}
+
+/* Test known_subrange_p for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_known_subrange_p ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  ASSERT_FALSE (known_subrange_p (ph::make (5, 1, 2),
+                                 ch::make (-1),
+                                 ch::make (4),
+                                 ph::make (2, 2, 2)));
+  ASSERT_FALSE (known_subrange_p (ph::make (5, 2, 3),
+                                 ch::make (2),
+                                 ph::make (4, 1, 2),
+                                 ch::make (-1)));
+  ASSERT_FALSE (known_subrange_p (ph::make (6, 2, 3),
+                                 ph::make (0, 1, 1),
+                                 ch::make (4),
+                                 ph::make (3, 4, 11)));
+  ASSERT_TRUE (known_subrange_p (ph::make (6, 2, 3),
+                                ph::make (1, 1, 1),
+                                ch::make (4),
+                                ph::make (3, 4, 11)));
+  ASSERT_FALSE (known_subrange_p (ph::make (6, 2, 3),
+                                 ph::make (1, 1, 1),
+                                 ch::make (4),
+                                 ph::make (2, 4, 11)));
+  ASSERT_TRUE (known_subrange_p (ph::make (10, 20, 30),
+                                ph::make (5, 6, 7),
+                                ph::make (9, 19, 29),
+                                ph::make (6, 7, 8)));
+  ASSERT_EQ (known_subrange_p (ph::make (10, 20, 31),
+                              ph::make (5, 6, 7),
+                              ph::make (9, 19, 29),
+                              ph::make (6, 7, 8)), N <= 2);
+  ASSERT_EQ (known_subrange_p (ph::make (10, 20, 30),
+                              ph::make (5, 7, 7),
+                              ph::make (9, 19, 29),
+                              ph::make (6, 7, 8)), N == 1);
+  ASSERT_EQ (known_subrange_p (ph::make (10, 20, 30),
+                              ph::make (5, 6, 7),
+                              ph::make (9, 18, 29),
+                              ph::make (6, 7, 8)), N == 1);
+  ASSERT_EQ (known_subrange_p (ph::make (10, 20, 30),
+                              ph::make (5, 6, 7),
+                              ph::make (9, 19, 29),
+                              ph::make (6, 6, 8)), N == 1);
+}
+
+/* Test coeffs_in_range_p for both signed and unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_coeffs_in_range_p (void)
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  ASSERT_TRUE (coeffs_in_range_p (ph::make (10, 20, 30), 10, 30));
+  ASSERT_EQ (coeffs_in_range_p (ph::make (1, 10, 19), 0, 11), N <= 2);
+  ASSERT_EQ (coeffs_in_range_p (ph::make (100, 1, 102), 10, 100), N == 1);
+  ASSERT_FALSE (coeffs_in_range_p (ph::make (10, 11, 12), 7, 9));
+  ASSERT_FALSE (coeffs_in_range_p (ph::make (10, 11, 12), 13, 15));
+}
+
+/* Test maybe_eq for poly_int<2, C>, given that C is signed.  */
+
+template<typename C>
+static void
+test_signed_maybe_eq_2 ()
+{
+  typedef poly_int<2, C> T;
+
+  /* Test maybe_eq (T, C).  */
+  ASSERT_TRUE (maybe_eq (T (4, -4), 0));
+  ASSERT_FALSE (maybe_eq (T (4, -4), 1));
+  ASSERT_TRUE (maybe_eq (T (4, -4), 4));
+  ASSERT_FALSE (maybe_eq (T (4, -4), 8));
+  ASSERT_TRUE (maybe_eq (T (4, -4), -4));
+  ASSERT_FALSE (maybe_eq (T (4, -4), -3));
+
+  /* Test maybe_eq (C, T).  */
+  ASSERT_FALSE (maybe_eq (0, T (4, -3)));
+  ASSERT_TRUE (maybe_eq (1, T (4, -3)));
+  ASSERT_TRUE (maybe_eq (4, T (4, -3)));
+  ASSERT_FALSE (maybe_eq (7, T (4, -3)));
+  ASSERT_FALSE (maybe_eq (T (4, -3), -3));
+  ASSERT_TRUE (maybe_eq (T (4, -3), -2));
+
+  /* Test maybe_eq (T, T).  */
+  ASSERT_TRUE (maybe_eq (T (0, 3), T (6, 1)));
+  ASSERT_FALSE (maybe_eq (T (0, -3), T (6, 1)));
+  ASSERT_FALSE (maybe_eq (T (0, 3), T (7, 1)));
+  ASSERT_TRUE (maybe_eq (T (-3, 4), T (7, -1)));
+  ASSERT_FALSE (maybe_eq (T (-3, 4), T (6, -1)));
+}
+
+/* Test known_ne for poly_int<2, C>, given that C is signed.  */
+
+template<typename C>
+static void
+test_signed_known_ne_2 ()
+{
+  typedef poly_int<2, C> T;
+
+  /* Test known_ne (T, C).  */
+  ASSERT_FALSE (known_ne (T (4, -4), 0));
+  ASSERT_TRUE (known_ne (T (4, -4), 1));
+  ASSERT_FALSE (known_ne (T (4, -4), 4));
+  ASSERT_TRUE (known_ne (T (4, -4), 8));
+  ASSERT_FALSE (known_ne (T (4, -4), -4));
+  ASSERT_TRUE (known_ne (T (4, -4), -3));
+
+  /* Test known_ne (C, T).  */
+  ASSERT_TRUE (known_ne (0, T (4, -3)));
+  ASSERT_FALSE (known_ne (1, T (4, -3)));
+  ASSERT_FALSE (known_ne (4, T (4, -3)));
+  ASSERT_TRUE (known_ne (7, T (4, -3)));
+  ASSERT_TRUE (known_ne (T (4, -3), -3));
+  ASSERT_FALSE (known_ne (T (4, -3), -2));
+
+  /* Test known_ne (T, T).  */
+  ASSERT_FALSE (known_ne (T (0, 3), T (6, 1)));
+  ASSERT_TRUE (known_ne (T (0, -3), T (6, 1)));
+  ASSERT_TRUE (known_ne (T (0, 3), T (7, 1)));
+  ASSERT_FALSE (known_ne (T (-3, 4), T (7, -1)));
+  ASSERT_TRUE (known_ne (T (-3, 4), T (6, -1)));
+}
+
+/* Test negation for signed C, both via operators and wi::.  */
+
+template<unsigned int N, typename C, typename RC, typename T>
+static void
+test_signed_negation ()
+{
+  typedef poly_helper<T> ph;
+  typedef poly_helper< poly_int<N, RC> > rph;
+  typedef poly_helper< poly_int<N, int> > iph;
+
+  /* Test unary -.  */
+  ASSERT_KNOWN_EQ (-ph::make (-11, 22, -33),
+                  rph::make (11, -22, 33));
+
+  /* Test wi::neg.  */
+  ASSERT_KNOWN_EQ (wi::neg (ph::make (-11, 22, -33)),
+                  iph::make (11, -22, 33));
+}
+
+/* Test maybe_le for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_maybe_le ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_le (T, C).  */
+  ASSERT_EQ (maybe_le (ph::make (3, 5, -1), ch::make (2)), N == 3);
+  ASSERT_EQ (maybe_le (ph::make (40, -10, 60), ch::make (15)), N >= 2);
+  ASSERT_TRUE (maybe_le (ph::make (-14, 0, 0), ch::make (13)));
+
+  /* Test maybe_le (C, T).  */
+  ASSERT_EQ (maybe_le (ch::make (4), ph::make (3, 5, -1)), N >= 2);
+  ASSERT_EQ (maybe_le (ch::make (41), ph::make (40, -10, 60)), N == 3);
+  ASSERT_TRUE (maybe_le (ch::make (-15), ph::make (11, 0, 0)));
+
+  /* Test maybe_le (T, T).  */
+  ASSERT_EQ (maybe_le (ph::make (-2, 4, -2),
+                      ph::make (-3, -5, -1)), N == 3);
+  ASSERT_EQ (maybe_le (ph::make (-2, -6, 0),
+                      ph::make (-3, 0, 100)), N >= 2);
+  ASSERT_FALSE (maybe_le (ph::make (-2, 5, 1),
+                         ph::make (-3, 4, 0)));
+}
+
+/* Test maybe_lt for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_maybe_lt ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_lt (T, C).  */
+  ASSERT_EQ (maybe_lt (ph::make (3, 5, -1), ch::make (2)), N == 3);
+  ASSERT_EQ (maybe_lt (ph::make (40, -10, 60), ch::make (15)), N >= 2);
+  ASSERT_TRUE (maybe_lt (ph::make (-18, 0, 0), ch::make (18)));
+  ASSERT_EQ (maybe_lt (ph::make (-2, -2, -2), ch::make (-2)), N >= 2);
+
+  /* Test maybe_lt (C, T).  */
+  ASSERT_EQ (maybe_lt (ch::make (4), ph::make (3, 5, -1)), N >= 2);
+  ASSERT_EQ (maybe_lt (ch::make (41), ph::make (40, -10, 60)), N == 3);
+  ASSERT_TRUE (maybe_lt (ch::make (-45), ph::make (40, 0, 0)));
+  ASSERT_FALSE (maybe_lt (ch::make (-2), ph::make (-2, -2, -2)));
+
+  /* Test maybe_lt (T, T).  */
+  ASSERT_EQ (maybe_lt (ph::make (-3, 4, -2),
+                      ph::make (-3, -5, -1)), N == 3);
+  ASSERT_EQ (maybe_lt (ph::make (-3, -6, 0),
+                      ph::make (-3, 0, 100)), N >= 2);
+  ASSERT_FALSE (maybe_lt (ph::make (-3, 5, 1),
+                         ph::make (-3, 4, 0)));
+}
+
+/* Test maybe_ge for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_maybe_ge ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_ge (T, C).  */
+  ASSERT_EQ (maybe_ge (ph::make (3, 5, -1), ch::make (4)), N >= 2);
+  ASSERT_EQ (maybe_ge (ph::make (40, -10, 60), ch::make (41)), N == 3);
+  ASSERT_TRUE (maybe_ge (ph::make (11, 0, 0), ch::make (-15)));
+
+  /* Test maybe_ge (C, T).  */
+  ASSERT_EQ (maybe_ge (ch::make (2), ph::make (3, 5, -1)), N == 3);
+  ASSERT_EQ (maybe_ge (ch::make (15), ph::make (40, -10, 60)), N >= 2);
+  ASSERT_TRUE (maybe_ge (ch::make (13), ph::make (-14, 0, 0)));
+
+  /* Test maybe_ge (T, T).  */
+  ASSERT_EQ (maybe_ge (ph::make (-3, -5, -1),
+                      ph::make (-2, 4, -2)), N == 3);
+  ASSERT_EQ (maybe_ge (ph::make (-3, 0, 100),
+                      ph::make (-2, -6, 0)), N >= 2);
+  ASSERT_FALSE (maybe_ge (ph::make (-3, 4, 0),
+                         ph::make (-2, 5, 1)));
+}
+
+/* Test maybe_gt for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_maybe_gt ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_gt (T, C).  */
+  ASSERT_EQ (maybe_gt (ph::make (3, 5, -1), ch::make (4)), N >= 2);
+  ASSERT_EQ (maybe_gt (ph::make (40, -10, 60), ch::make (41)), N == 3);
+  ASSERT_TRUE (maybe_gt (ph::make (40, 0, 0), ch::make (-45)));
+  ASSERT_FALSE (maybe_gt (ph::make (-2, -2, -2), ch::make (-2)));
+
+  /* Test maybe_gt (C, T).  */
+  ASSERT_EQ (maybe_gt (ch::make (2), ph::make (3, 5, -1)), N == 3);
+  ASSERT_EQ (maybe_gt (ch::make (15), ph::make (40, -10, 60)), N >= 2);
+  ASSERT_TRUE (maybe_gt (ch::make (18), ph::make (-18, 0, 0)));
+  ASSERT_EQ (maybe_gt (ch::make (-2), ph::make (-2, -2, -2)), N >= 2);
+
+  /* Test maybe_gt (T, T).  */
+  ASSERT_EQ (maybe_gt (ph::make (-3, -5, -1),
+                      ph::make (-3, 4, -2)), N == 3);
+  ASSERT_EQ (maybe_gt (ph::make (-3, 0, 100),
+                      ph::make (-3, -6, 0)), N >= 2);
+  ASSERT_FALSE (maybe_gt (ph::make (-3, 4, 0),
+                         ph::make (-3, 5, 1)));
+}
+
+/* Test known_gt for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_known_gt ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_gt (T, C).  */
+  ASSERT_EQ (known_gt (ph::make (3, 5, -1), ch::make (2)), N <= 2);
+  ASSERT_EQ (known_gt (ph::make (40, -10, 60), ch::make (15)), N == 1);
+  ASSERT_FALSE (known_gt (ph::make (-14, 0, 0), ch::make (13)));
+
+  /* Test known_gt (C, T).  */
+  ASSERT_EQ (known_gt (ch::make (4), ph::make (3, 5, -1)), N == 1);
+  ASSERT_EQ (known_gt (ch::make (41), ph::make (40, -10, 60)), N <= 2);
+  ASSERT_FALSE (known_gt (ch::make (-15), ph::make (11, 0, 0)));
+
+  /* Test known_gt (T, T).  */
+  ASSERT_EQ (known_gt (ph::make (-2, 4, -2),
+                      ph::make (-3, -5, -1)), N <= 2);
+  ASSERT_EQ (known_gt (ph::make (-2, -6, 0),
+                      ph::make (-3, 0, 100)), N == 1);
+  ASSERT_TRUE (known_gt (ph::make (-2, 5, 1),
+                        ph::make (-3, 4, 0)));
+}
+
+/* Test known_ge for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_known_ge ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_ge (T, C).  */
+  ASSERT_EQ (known_ge (ph::make (3, 5, -1), ch::make (2)), N <= 2);
+  ASSERT_EQ (known_ge (ph::make (40, -10, 60), ch::make (15)), N == 1);
+  ASSERT_FALSE (known_ge (ph::make (-18, 0, 0), ch::make (18)));
+  ASSERT_EQ (known_ge (ph::make (-2, -2, -2), ch::make (-2)), N == 1);
+
+  /* Test known_ge (C, T).  */
+  ASSERT_EQ (known_ge (ch::make (4), ph::make (3, 5, -1)), N == 1);
+  ASSERT_EQ (known_ge (ch::make (41), ph::make (40, -10, 60)), N <= 2);
+  ASSERT_FALSE (known_ge (ch::make (-45), ph::make (40, 0, 0)));
+  ASSERT_TRUE (known_ge (ch::make (-2), ph::make (-2, -2, -2)));
+
+  /* Test known_ge (T, T).  */
+  ASSERT_EQ (known_ge (ph::make (-3, 4, -2),
+                      ph::make (-3, -5, -1)), N <= 2);
+  ASSERT_EQ (known_ge (ph::make (-3, -6, 0),
+                      ph::make (-3, 0, 100)), N == 1);
+  ASSERT_TRUE (known_ge (ph::make (-3, 5, 1),
+                        ph::make (-3, 4, 0)));
+}
+
+/* Test known_lt for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_known_lt ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_lt (T, C).  */
+  ASSERT_EQ (known_lt (ph::make (3, 5, -1), ch::make (4)), N == 1);
+  ASSERT_EQ (known_lt (ph::make (40, -10, 60), ch::make (41)), N <= 2);
+  ASSERT_FALSE (known_lt (ph::make (11, 0, 0), ch::make (-15)));
+
+  /* Test known_lt (C, T).  */
+  ASSERT_EQ (known_lt (ch::make (2), ph::make (3, 5, -1)), N <= 2);
+  ASSERT_EQ (known_lt (ch::make (15), ph::make (40, -10, 60)), N == 1);
+  ASSERT_FALSE (known_lt (ch::make (13), ph::make (-14, 0, 0)));
+
+  /* Test known_lt (T, T).  */
+  ASSERT_EQ (known_lt (ph::make (-3, -5, -1),
+                      ph::make (-2, 4, -2)), N <= 2);
+  ASSERT_EQ (known_lt (ph::make (-3, 0, 100),
+                      ph::make (-2, -6, 0)), N == 1);
+  ASSERT_TRUE (known_lt (ph::make (-3, 4, 0),
+                        ph::make (-2, 5, 1)));
+}
+
+/* Test known_le for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_known_le ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_le (T, C).  */
+  ASSERT_EQ (known_le (ph::make (3, 5, -1), ch::make (4)), N == 1);
+  ASSERT_EQ (known_le (ph::make (40, -10, 60), ch::make (41)), N <= 2);
+  ASSERT_FALSE (known_le (ph::make (40, 0, 0), ch::make (-45)));
+  ASSERT_TRUE (known_le (ph::make (-2, -2, -2), ch::make (-2)));
+
+  /* Test known_le (C, T).  */
+  ASSERT_EQ (known_le (ch::make (2), ph::make (3, 5, -1)), N <= 2);
+  ASSERT_EQ (known_le (ch::make (15), ph::make (40, -10, 60)), N == 1);
+  ASSERT_FALSE (known_le (ch::make (18), ph::make (-18, 0, 0)));
+  ASSERT_EQ (known_le (ch::make (-2), ph::make (-2, -2, -2)), N == 1);
+
+  /* Test known_le (T, T).  */
+  ASSERT_EQ (known_le (ph::make (-3, -5, -1),
+                      ph::make (-3, 4, -2)), N <= 2);
+  ASSERT_EQ (known_le (ph::make (-3, 0, 100),
+                      ph::make (-3, -6, 0)), N == 1);
+  ASSERT_TRUE (known_le (ph::make (-3, 4, 0),
+                        ph::make (-3, 5, 1)));
+}
+
+/* Test ordered_p for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_ordered_p ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test ordered_p (T, C).  */
+  ASSERT_EQ (ordered_p (ph::make (3, 5, -1), ch::make (4)), N == 1);
+  ASSERT_EQ (ordered_p (ph::make (3, 5, -1), ch::make (3)), N <= 2);
+  ASSERT_EQ (ordered_p (ph::make (3, 5, -1), ch::make (2)), N <= 2);
+  ASSERT_EQ (ordered_p (ph::make (40, -10, 60), ch::make (41)), N <= 2);
+  ASSERT_EQ (ordered_p (ph::make (40, -10, 60), ch::make (40)), N <= 2);
+  ASSERT_EQ (ordered_p (ph::make (40, -10, 60), ch::make (39)), N == 1);
+  ASSERT_EQ (ordered_p (ph::make (4, -4, -4), ch::make (0)), N == 1);
+  ASSERT_EQ (ordered_p (ph::make (4, 0, -4), ch::make (0)), N <= 2);
+  ASSERT_EQ (ordered_p (ph::make (4, 4, -4), ch::make (0)), N <= 2);
+  ASSERT_EQ (ordered_p (ph::make (-4, 4, 4), ch::make (0)), N == 1);
+  ASSERT_EQ (ordered_p (ph::make (-4, 0, 4), ch::make (0)), N <= 2);
+  ASSERT_EQ (ordered_p (ph::make (-4, -4, 4), ch::make (0)), N <= 2);
+
+  /* Test ordered_p (C, T).  */
+  ASSERT_EQ (ordered_p (ch::make (4), ph::make (3, 5, -1)), N == 1);
+  ASSERT_EQ (ordered_p (ch::make (3), ph::make (3, 5, -1)), N <= 2);
+  ASSERT_EQ (ordered_p (ch::make (2), ph::make (3, 5, -1)), N <= 2);
+  ASSERT_EQ (ordered_p (ch::make (41), ph::make (40, -10, 60)), N <= 2);
+  ASSERT_EQ (ordered_p (ch::make (40), ph::make (40, -10, 60)), N <= 2);
+  ASSERT_EQ (ordered_p (ch::make (39), ph::make (40, -10, 60)), N == 1);
+  ASSERT_EQ (ordered_p (ch::make (0), ph::make (4, -4, -4)), N == 1);
+  ASSERT_EQ (ordered_p (ch::make (0), ph::make (4, 0, -4)), N <= 2);
+  ASSERT_EQ (ordered_p (ch::make (0), ph::make (4, 4, -4)), N <= 2);
+  ASSERT_EQ (ordered_p (ch::make (0), ph::make (-4, 4, 4)), N == 1);
+  ASSERT_EQ (ordered_p (ch::make (0), ph::make (-4, 0, 4)), N <= 2);
+  ASSERT_EQ (ordered_p (ch::make (0), ph::make (-4, -4, 4)), N <= 2);
+}
+
+/* Test ordered_min for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_ordered_min ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test ordered_min (T, C).  */
+  ASSERT_KNOWN_EQ (ordered_min (ph::make (4, -12, -14), ch::make (5)),
+                  ph::make (4, -12, -14));
+
+  /* Test ordered_min (C, T).  */
+  ASSERT_KNOWN_EQ (ordered_min (ch::make (9), ph::make (9, -90, -77)),
+                  ph::make (9, -90, -77));
+
+  /* Test ordered_min (T, T).  */
+  ASSERT_KNOWN_EQ (ordered_min (ph::make (4, 9, 17), ph::make (4, -1, 17)),
+                  ph::make (4, -1, 17));
+}
+
+/* Test ordered_max for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_ordered_max ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test ordered_max (T, C).  */
+  ASSERT_KNOWN_EQ (ordered_max (ph::make (4, -12, -14), ch::make (5)),
+                  ch::make (5));
+
+  /* Test ordered_max (C, T).  */
+  ASSERT_KNOWN_EQ (ordered_max (ch::make (9), ph::make (9, -90, -77)),
+                  ch::make (9));
+
+  /* Test ordered_max (T, T).  */
+  ASSERT_KNOWN_EQ (ordered_max (ph::make (4, 9, 17), ph::make (4, -1, 17)),
+                  ph::make (4, 9, 17));
+}
+
+/* Test lower_bound for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_lower_bound ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test lower_bound (T, C).  */
+  ASSERT_KNOWN_EQ (lower_bound (ph::make (4, -1, 3), ch::make (5)),
+                  ph::make (4, -1, 0));
+  ASSERT_KNOWN_EQ (lower_bound (ph::make (6, 5, -14), ch::make (-11)),
+                  ph::make (-11, 0, -14));
+
+  /* Test lower_bound (C, T).  */
+  ASSERT_KNOWN_EQ (lower_bound (ch::make (5), ph::make (4, -1, 3)),
+                  ph::make (4, -1, 0));
+  ASSERT_KNOWN_EQ (lower_bound (ch::make (-11), ph::make (6, 5, -14)),
+                  ph::make (-11, 0, -14));
+
+  /* Test lower_bound (T, T).  */
+  ASSERT_KNOWN_EQ (lower_bound (ph::make (4, -1, 3), ph::make (5, 7, -2)),
+                  ph::make (4, -1, -2));
+  ASSERT_KNOWN_EQ (lower_bound (ph::make (6, 5, -14), ph::make (-11, 4, 3)),
+                  ph::make (-11, 4, -14));
+}
+
+/* Test upper_bound for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_upper_bound ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test upper_bound (T, C).  */
+  ASSERT_KNOWN_EQ (upper_bound (ph::make (4, -1, 3), ch::make (5)),
+                  ph::make (5, 0, 3));
+  ASSERT_KNOWN_EQ (upper_bound (ph::make (6, 5, -14), ch::make (-11)),
+                  ph::make (6, 5, 0));
+
+  /* Test upper_bound (C, T).  */
+  ASSERT_KNOWN_EQ (upper_bound (ch::make (5), ph::make (4, -1, 3)),
+                  ph::make (5, 0, 3));
+  ASSERT_KNOWN_EQ (upper_bound (ch::make (-11), ph::make (6, 5, -14)),
+                  ph::make (6, 5, 0));
+
+  /* Test upper_bound (T, T).  */
+  ASSERT_KNOWN_EQ (upper_bound (ph::make (4, -1, 3), ph::make (5, 7, -2)),
+                  ph::make (5, 7, 3));
+  ASSERT_KNOWN_EQ (upper_bound (ph::make (6, 5, -14), ph::make (-11, 4, 3)),
+                  ph::make (6, 5, 3));
+}
+
+/* Test constant_multiple_p for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_constant_multiple_p ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test constant_multiple_p (T, C).  */
+  C const_multiple;
+  ASSERT_TRUE (constant_multiple_p (ph::make (-45, 0, 0), 9,
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, -5);
+  ASSERT_TRUE (constant_multiple_p (ph::make (63, 0, 0), -7,
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, -9);
+  ASSERT_FALSE (constant_multiple_p (ph::make (-121, 0, 0), -12,
+                                    &const_multiple));
+  ASSERT_TRUE (constant_multiple_p (ph::make (-120, 0, 0), -12,
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, 10);
+  ASSERT_FALSE (constant_multiple_p (ph::make (-119, 0, 0), -12,
+                                    &const_multiple));
+  ASSERT_EQ (constant_multiple_p (ph::make (-120, -23, 12), 12,
+                                 &const_multiple), N == 1);
+  if (N == 1)
+    ASSERT_EQ (const_multiple, -10);
+
+  /* Test constant_multiple_p (C, T).  */
+  ASSERT_TRUE (constant_multiple_p (-45, ph::make (9, 0, 0),
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, -5);
+  ASSERT_TRUE (constant_multiple_p (63, ph::make (-7, 0, 0),
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, -9);
+  ASSERT_FALSE (constant_multiple_p (-121, ph::make (-12, 0, 0),
+                                    &const_multiple));
+  ASSERT_TRUE (constant_multiple_p (-120, ph::make (-12, 0, 0),
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, 10);
+  ASSERT_FALSE (constant_multiple_p (-119, ph::make (-12, 0, 0),
+                                    &const_multiple));
+  ASSERT_EQ (constant_multiple_p (-120, ph::make (12, 10, 6),
+                                 &const_multiple), N == 1);
+  if (N == 1)
+    ASSERT_EQ (const_multiple, -10);
+
+  ASSERT_TRUE (constant_multiple_p (ph::make (-40, 80, -200),
+                                   ph::make (2, -4, 10),
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, -20);
+  ASSERT_EQ (constant_multiple_p (ph::make (-20, 40, 100),
+                                 ph::make (2, -4, 10),
+                                 &const_multiple), N <= 2);
+  ASSERT_EQ (const_multiple, N <= 2 ? -10 : -20);
+  ASSERT_EQ (constant_multiple_p (ph::make (-10, -20, -50),
+                                 ph::make (2, -4, 10),
+                                 &const_multiple), N == 1);
+  ASSERT_EQ (const_multiple, N == 1 ? -5 : N == 2 ? -10 : -20);
+  ASSERT_FALSE (constant_multiple_p (ph::make (-31, 0, 0),
+                                    ph::make (-6, 0, 0),
+                                    &const_multiple));
+  ASSERT_TRUE (constant_multiple_p (ph::make (-30, 0, 0),
+                                   ph::make (-6, 0, 0),
+                                   &const_multiple));
+  ASSERT_EQ (const_multiple, 5);
+  ASSERT_FALSE (constant_multiple_p (ph::make (-29, 0, 0),
+                                    ph::make (-6, 0, 0),
+                                    &const_multiple));
+}
+
+/* Test multiple_p for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_multiple_p ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test multiple_p (T, C).  */
+  ASSERT_TRUE (multiple_p (ph::make (-45, 36, 0), 9));
+  ASSERT_TRUE (multiple_p (ph::make (63, 0, -14), -7));
+  ASSERT_FALSE (multiple_p (ph::make (-121, 0, 0), -12));
+  ASSERT_TRUE (multiple_p (ph::make (-120, 0, 0), -12));
+  ASSERT_FALSE (multiple_p (ph::make (-119, 0, 0), -12));
+  ASSERT_TRUE (multiple_p (ph::make (-120, -24, 12), 12));
+  ASSERT_EQ (multiple_p (ph::make (-120, -24, 11), 12), N <= 2);
+  ASSERT_EQ (multiple_p (ph::make (-120, -23, 12), 12), N == 1);
+
+  /* Test multiple_p (C, T).  */
+  ASSERT_TRUE (multiple_p (-45, ph::make (9, 0, 0)));
+  ASSERT_TRUE (multiple_p (63, ph::make (-7, 0, 0)));
+  ASSERT_FALSE (multiple_p (-121, ph::make (-12, 0, 0)));
+  ASSERT_TRUE (multiple_p (-120, ph::make (-12, 0, 0)));
+  ASSERT_FALSE (multiple_p (-119, ph::make (-12, 0, 0)));
+  ASSERT_EQ (multiple_p (-120, ph::make (12, 10, 6)), N == 1);
+
+  /* Test multiple_p (T, T).  */
+  ASSERT_TRUE (multiple_p (ph::make (-40, 80, -200),
+                          ph::make (2, -4, 10)));
+  ASSERT_EQ (multiple_p (ph::make (-20, 40, 100),
+                        ph::make (2, -4, 10)), N <= 2);
+  ASSERT_EQ (multiple_p (ph::make (-10, -20, -50),
+                        ph::make (2, -4, 10)), N == 1);
+  ASSERT_FALSE (multiple_p (ph::make (-31, 0, 0),
+                           ph::make (-6, 0, 0)));
+  ASSERT_TRUE (multiple_p (ph::make (-30, 0, 0),
+                          ph::make (-6, 0, 0)));
+  ASSERT_FALSE (multiple_p (ph::make (-29, 0, 0),
+                           ph::make (-6, 0, 0)));
+}
+
+/* Test the 3-operand form of multiple_p for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_multiple_p_with_result ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test multiple_p (T, C) -> T.  */
+  T multiple;
+  ASSERT_TRUE (multiple_p (ph::make (-45, 36, 0), 9, &multiple));
+  ASSERT_KNOWN_EQ (multiple, ph::make (-5, 4, 0));
+  ASSERT_TRUE (multiple_p (ph::make (63, 0, -14), -7, &multiple));
+  ASSERT_KNOWN_EQ (multiple, ph::make (-9, 0, 2));
+  ASSERT_FALSE (multiple_p (ph::make (-121, 0, 0), -12, &multiple));
+  ASSERT_TRUE (multiple_p (ph::make (-120, 0, 0), -12, &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (10));
+  ASSERT_FALSE (multiple_p (ph::make (-119, 0, 0), -12, &multiple));
+  ASSERT_TRUE (multiple_p (ph::make (-120, -24, 12), 12, &multiple));
+  ASSERT_KNOWN_EQ (multiple, ph::make (-10, -2, 1));
+  ASSERT_EQ (multiple_p (ph::make (-120, -24, 11), 12, &multiple), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (multiple, ph::make (-10, -2, 0));
+  ASSERT_EQ (multiple_p (ph::make (-120, -23, 12), 12, &multiple), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (multiple, ch::make (-10));
+
+  /* Test multiple_p (C, T) -> T.  */
+  ASSERT_TRUE (multiple_p (-45, ph::make (9, 0, 0), &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (-5));
+  ASSERT_TRUE (multiple_p (63, ph::make (-7, 0, 0), &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (-9));
+  ASSERT_FALSE (multiple_p (-121, ph::make (-12, 0, 0), &multiple));
+  ASSERT_TRUE (multiple_p (-120, ph::make (-12, 0, 0), &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (10));
+  ASSERT_FALSE (multiple_p (-119, ph::make (-12, 0, 0), &multiple));
+  ASSERT_EQ (multiple_p (-120, ph::make (12, 10, 6), &multiple), N == 1);
+  ASSERT_KNOWN_EQ (multiple, ch::make (N == 1 ? -10 : 10));
+
+  /* Test multiple_p (T, T) -> T.  */
+  ASSERT_TRUE (multiple_p (ph::make (-40, 80, -200),
+                          ph::make (2, -4, 10),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (-20));
+  ASSERT_EQ (multiple_p (ph::make (-20, 40, 100),
+                        ph::make (2, -4, 10),
+                        &multiple), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (multiple, ch::make (-10));
+  ASSERT_EQ (multiple_p (ph::make (-10, -20, -50),
+                        ph::make (2, -4, 10),
+                        &multiple), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (multiple, ch::make (-5));
+  ASSERT_FALSE (multiple_p (ph::make (-31, 0, 0),
+                           ph::make (-6, 0, 0),
+                           &multiple));
+  ASSERT_TRUE (multiple_p (ph::make (-30, 0, 0),
+                          ph::make (-6, 0, 0),
+                          &multiple));
+  ASSERT_KNOWN_EQ (multiple, ch::make (5));
+  ASSERT_FALSE (multiple_p (ph::make (-29, 0, 0),
+                           ph::make (-6, 0, 0),
+                           &multiple));
+}
+
+/* Test exact_div for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_exact_div ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test exact_div (T, C).  */
+  ASSERT_KNOWN_EQ (exact_div (ph::make (-45, 36, 0), 9),
+                  ph::make (-5, 4, 0));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (63, 0, -14), -7),
+                  ph::make (-9, 0, 2));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (-120, 0, 0), -12),
+                  ch::make (10));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (-120, -24, 12), 12),
+                  ph::make (-10, -2, 1));
+
+  /* Test exact_div (T, T).  */
+  ASSERT_KNOWN_EQ (exact_div (ph::make (-40, 80, -200),
+                             ph::make (2, -4, 10)),
+                  ch::make (-20));
+  ASSERT_KNOWN_EQ (exact_div (ph::make (-30, 0, 0),
+                             ph::make (-6, 0, 0)),
+                  ch::make (5));
+}
+
+/* Test the form of can_div_trunc_p that returns a constant, for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_can_div_trunc_p_const ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test can_div_trunc_p (T, C) -> C.  */
+  C const_quot;
+  ASSERT_TRUE (can_div_trunc_p (ph::make (-31, 0, 0), 10, &const_quot));
+  ASSERT_KNOWN_EQ (const_quot, -3);
+  ASSERT_TRUE (can_div_trunc_p (ph::make (-29, 0, 0), 10, &const_quot));
+  ASSERT_KNOWN_EQ (const_quot, -2);
+
+  /* Test can_div_trunc_p (T, T) -> C.  */
+  ASSERT_TRUE (can_div_trunc_p (ph::make (-10, 25, -15),
+                               ph::make (2, -5, 3),
+                               &const_quot));
+  ASSERT_EQ (const_quot, -5);
+  /* (-5 + 2x) / (-3 + 2x) != 1 when x == 1.  */
+  ASSERT_EQ (can_div_trunc_p (ph::make (-5, 2, 0),
+                             ph::make (-3, 2, 0),
+                             &const_quot), N == 1);
+  ASSERT_EQ (const_quot, N == 1 ? 1 : -5);
+  /* Similarly for the third coefficient.  */
+  ASSERT_EQ (can_div_trunc_p (ph::make (-5, -5, 2),
+                             ph::make (-3, -3, 2),
+                             &const_quot), N <= 2);
+  ASSERT_EQ (const_quot, N <= 2 ? 1 : -5);
+  /* (-15 + 3x) / (-12 + 2x) != 1 when x == 7.  */
+  ASSERT_EQ (can_div_trunc_p (ph::make (-15, 3, 0),
+                             ph::make (-12, 2, 0),
+                             &const_quot), N == 1);
+  ASSERT_EQ (const_quot, N <= 2 ? 1 : -5);
+  ASSERT_TRUE (can_div_trunc_p (ph::make (-21, -18, -14),
+                               ph::make (5, 4, 3),
+                               &const_quot));
+  ASSERT_EQ (const_quot, -4);
+  ASSERT_TRUE (can_div_trunc_p (ph::make (18, 9, 13),
+                               ph::make (-8, -4, -5),
+                               &const_quot));
+  ASSERT_EQ (const_quot, -2);
+
+  /* Test can_div_trunc_p (T, T) -> C, T.  */
+  T rem;
+  ASSERT_TRUE (can_div_trunc_p (ph::make (-10, 25, -15),
+                               ph::make (2, -5, 3),
+                               &const_quot, &rem));
+  ASSERT_EQ (const_quot, -5);
+  ASSERT_KNOWN_EQ (rem, ch::make (0));
+  /* (-5 + 2x) / (-3 + 2x) != 1 when x == 1.  */
+  ASSERT_EQ (can_div_trunc_p (ph::make (-5, 2, 0),
+                             ph::make (-3, 2, 0),
+                             &const_quot, &rem), N == 1);
+  ASSERT_KNOWN_EQ (const_quot, N == 1 ? 1 : -5);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (rem, ch::make (-2));
+  /* Similarly for the third coefficient.  */
+  ASSERT_EQ (can_div_trunc_p (ph::make (-5, -5, 2),
+                             ph::make (-3, -3, 2),
+                             &const_quot, &rem), N <= 2);
+  ASSERT_KNOWN_EQ (const_quot, N <= 2 ? 1 : -5);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (rem, ph::make (-2, -2, 0));
+  /* (-15 + 3x) / (-12 + 2x) != 1 when x == 7.  */
+  ASSERT_EQ (can_div_trunc_p (ph::make (-15, 3, 0),
+                             ph::make (-12, 2, 0),
+                             &const_quot, &rem), N == 1);
+  ASSERT_KNOWN_EQ (const_quot, N <= 2 ? 1 : -5);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (rem, ch::make (-3));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (-21, -18, -14),
+                               ph::make (5, 4, 3),
+                               &const_quot, &rem));
+  ASSERT_EQ (const_quot, -4);
+  ASSERT_KNOWN_EQ (rem, ph::make (-1, -2, -2));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (18, 9, 13),
+                               ph::make (-8, -4, -5),
+                               &const_quot, &rem));
+  ASSERT_EQ (const_quot, -2);
+  ASSERT_KNOWN_EQ (rem, ph::make (2, 1, 3));
+}
+
+/* Test the form of can_div_trunc_p that returns a poly_int, for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_can_div_trunc_p_poly ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test can_div_trunc_p (T, C) -> T.  */
+  T quot;
+  ASSERT_TRUE (can_div_trunc_p (ph::make (-99, 0, 0), 10, &quot));
+  ASSERT_KNOWN_EQ (quot, ch::make (-9));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (7, -63, 81), 9, &quot));
+  ASSERT_KNOWN_EQ (quot, ph::make (0, -7, 9));
+  ASSERT_TRUE (can_div_trunc_p (ph::make (15, 44, -55), -11, &quot));
+  ASSERT_KNOWN_EQ (quot, ph::make (-1, -4, 5));
+  ASSERT_EQ (can_div_trunc_p (ph::make (-63, -24, -17), -8, &quot), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (quot, ph::make (7, 3, 0));
+  ASSERT_EQ (can_div_trunc_p (ph::make (40, 48, 70), -7, &quot), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (quot, ch::make (-5));
+
+  /* Test can_div_trunc_p (T, C) -> T, C.  */
+  C const_rem;
+  ASSERT_TRUE (can_div_trunc_p (ph::make (-99, 0, 0), 10,
+                               &quot, &const_rem));
+  ASSERT_KNOWN_EQ (quot, ch::make (-9));
+  ASSERT_EQ (const_rem, -9);
+  ASSERT_TRUE (can_div_trunc_p (ph::make (7, -63, 81), 9,
+                               &quot, &const_rem));
+  ASSERT_KNOWN_EQ (quot, ph::make (0, -7, 9));
+  ASSERT_EQ (const_rem, 7);
+  ASSERT_TRUE (can_div_trunc_p (ph::make (15, 44, -55), -11,
+                               &quot, &const_rem));
+  ASSERT_KNOWN_EQ (quot, ph::make (-1, -4, 5));
+  ASSERT_EQ (const_rem, 4);
+  ASSERT_EQ (can_div_trunc_p (ph::make (-63, -24, -17), -8,
+                             &quot, &const_rem), N <= 2);
+  if (N <= 2)
+    {
+      ASSERT_KNOWN_EQ (quot, ph::make (7, 3, 0));
+      ASSERT_EQ (const_rem, -7);
+    }
+  ASSERT_EQ (can_div_trunc_p (ph::make (40, 48, 70), -7,
+                             &quot, &const_rem), N == 1);
+  if (N == 1)
+    {
+      ASSERT_KNOWN_EQ (quot, ch::make (-5));
+      ASSERT_EQ (const_rem, 5);
+    }
+}
+
+/* Test can_div_away_from_zero_p for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_can_div_away_from_zero_p ()
+{
+  typedef poly_helper<T> ph;
+
+  /* Test can_div_away_from_zero_p (T, T) -> C.  */
+  C const_quot;
+  ASSERT_TRUE (can_div_away_from_zero_p (ph::make (-10, 25, -15),
+                                        ph::make (2, -5, 3),
+                                        &const_quot));
+  ASSERT_EQ (const_quot, -5);
+  /* (-5 + 2x) / (-3 + 2x) != 1 when x == 1.  */
+  ASSERT_EQ (can_div_away_from_zero_p (ph::make (-5, 2, 0),
+                                      ph::make (-3, 2, 0),
+                                      &const_quot), N == 1);
+  ASSERT_EQ (const_quot, N == 1 ? 2 : -5);
+  /* Similarly for the third coefficient.  */
+  ASSERT_EQ (can_div_away_from_zero_p (ph::make (-5, -5, 2),
+                                      ph::make (-3, -3, 2),
+                                      &const_quot), N <= 2);
+  ASSERT_EQ (const_quot, N <= 2 ? 2 : -5);
+  /* (-15 + 3x) / (-12 + 2x) != 1 when x == 7.  */
+  ASSERT_EQ (can_div_away_from_zero_p (ph::make (-15, 3, 0),
+                                      ph::make (-12, 2, 0),
+                                      &const_quot), N == 1);
+  ASSERT_EQ (const_quot, N <= 2 ? 2 : -5);
+  ASSERT_TRUE (can_div_away_from_zero_p (ph::make (-21, -18, -14),
+                                        ph::make (5, 4, 3),
+                                        &const_quot));
+  ASSERT_EQ (const_quot, -5);
+  ASSERT_TRUE (can_div_away_from_zero_p (ph::make (18, 9, 13),
+                                        ph::make (-8, -4, -5),
+                                        &const_quot));
+  ASSERT_EQ (const_quot, -3);
+}
+
+/* Test maybe_in_range_p for signed C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_signed_maybe_in_range_p ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  ASSERT_EQ (maybe_in_range_p (ch::make (4),
+                              ph::make (5, 1, -2),
+                              ph::make (-1, -1, -1)), N == 3);
+  ASSERT_EQ (maybe_in_range_p (ch::make (4),
+                              ph::make (5, -1, 2),
+                              ph::make (-1, -1, -1)), N >= 2);
+}
+
+/* Test maybe_le for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_maybe_le ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_le (T, C).  */
+  ASSERT_FALSE (maybe_le (ph::make (3, 5, -1), ch::make (2)));
+  ASSERT_FALSE (maybe_le (ph::make (40, -10, 60), ch::make (15)));
+  ASSERT_FALSE (maybe_le (ph::make (-14, 0, 0), ch::make (13)));
+
+  /* Test maybe_le (C, T).  */
+  ASSERT_EQ (maybe_le (ch::make (4), ph::make (3, 5, -1)), N >= 2);
+  ASSERT_EQ (maybe_le (ch::make (41), ph::make (40, -10, 60)), N >= 2);
+  ASSERT_FALSE (maybe_le (ch::make (-15), ph::make (11, 0, 0)));
+
+  /* Test maybe_le (T, T).  */
+  ASSERT_EQ (maybe_le (ph::make (-2, 4, -2),
+                      ph::make (-3, -5, -1)), N >= 2);
+  ASSERT_EQ (maybe_le (ph::make (-2, -6, 0),
+                      ph::make (-3, 0, 100)), N == 3);
+  ASSERT_FALSE (maybe_le (ph::make (-2, 5, 1),
+                         ph::make (-3, 4, 0)));
+}
+
+/* Test maybe_lt for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_maybe_lt ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_lt (T, C).  */
+  ASSERT_FALSE (maybe_lt (ph::make (3, 5, -1), ch::make (2)));
+  ASSERT_FALSE (maybe_lt (ph::make (40, -10, 60), ch::make (15)));
+  ASSERT_FALSE (maybe_lt (ph::make (-18, 0, 0), ch::make (18)));
+  ASSERT_FALSE (maybe_lt (ph::make (-2, -2, -2), ch::make (-2)));
+
+  /* Test maybe_lt (C, T).  */
+  ASSERT_EQ (maybe_lt (ch::make (4), ph::make (3, 5, -1)), N >= 2);
+  ASSERT_EQ (maybe_lt (ch::make (41), ph::make (40, -10, 60)), N >= 2);
+  ASSERT_FALSE (maybe_lt (ch::make (-45), ph::make (40, 0, 0)));
+  ASSERT_EQ (maybe_lt (ch::make (-2), ph::make (-2, -2, -2)), N >= 2);
+
+  /* Test maybe_lt (T, T).  */
+  ASSERT_EQ (maybe_lt (ph::make (-3, 4, -2),
+                      ph::make (-3, -5, -1)), N >= 2);
+  ASSERT_EQ (maybe_lt (ph::make (-3, -6, 0),
+                      ph::make (-3, 0, 100)), N == 3);
+  ASSERT_FALSE (maybe_lt (ph::make (-3, 5, 1),
+                         ph::make (-3, 4, 0)));
+}
+
+/* Test maybe_ge for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_maybe_ge ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_ge (T, C).  */
+  ASSERT_EQ (maybe_ge (ph::make (3, 5, -1), ch::make (4)), N >= 2);
+  ASSERT_EQ (maybe_ge (ph::make (40, -10, 60), ch::make (41)), N >= 2);
+  ASSERT_FALSE (maybe_ge (ph::make (11, 0, 0), ch::make (-15)));
+
+  /* Test maybe_ge (C, T).  */
+  ASSERT_FALSE (maybe_ge (ch::make (2), ph::make (3, 5, -1)));
+  ASSERT_FALSE (maybe_ge (ch::make (15), ph::make (40, -10, 60)));
+  ASSERT_FALSE (maybe_ge (ch::make (13), ph::make (-14, 0, 0)));
+
+  /* Test maybe_ge (T, T).  */
+  ASSERT_EQ (maybe_ge (ph::make (-3, -5, -1),
+                      ph::make (-2, 4, -2)), N >= 2);
+  ASSERT_EQ (maybe_ge (ph::make (-3, 0, 100),
+                      ph::make (-2, -6, 0)), N == 3);
+  ASSERT_FALSE (maybe_ge (ph::make (-3, 4, 0),
+                         ph::make (-2, 5, 1)));
+}
+
+/* Test maybe_gt for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_maybe_gt ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test maybe_gt (T, C).  */
+  ASSERT_EQ (maybe_gt (ph::make (3, 5, -1), ch::make (4)), N >= 2);
+  ASSERT_EQ (maybe_gt (ph::make (40, -10, 60), ch::make (41)), N >= 2);
+  ASSERT_FALSE (maybe_gt (ph::make (40, 0, 0), ch::make (-45)));
+  ASSERT_EQ (maybe_gt (ph::make (-2, -2, -2), ch::make (-2)), N >= 2);
+
+  /* Test maybe_gt (C, T).  */
+  ASSERT_FALSE (maybe_gt (ch::make (2), ph::make (3, 5, -1)));
+  ASSERT_FALSE (maybe_gt (ch::make (15), ph::make (40, -10, 60)));
+  ASSERT_FALSE (maybe_gt (ch::make (18), ph::make (-18, 0, 0)));
+  ASSERT_FALSE (maybe_gt (ch::make (-2), ph::make (-2, -2, -2)));
+
+  /* Test maybe_gt (T, T).  */
+  ASSERT_EQ (maybe_gt (ph::make (-3, -5, -1),
+                      ph::make (-3, 4, -2)), N >= 2);
+  ASSERT_EQ (maybe_gt (ph::make (-3, 0, 100),
+                      ph::make (-3, -6, 0)), N == 3);
+  ASSERT_FALSE (maybe_gt (ph::make (-3, 4, 0),
+                         ph::make (-3, 5, 1)));
+}
+
+/* Test known_gt for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_known_gt ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_gt (T, C).  */
+  ASSERT_TRUE (known_gt (ph::make (3, 5, -1), ch::make (2)));
+  ASSERT_TRUE (known_gt (ph::make (40, -10, 60), ch::make (15)));
+  ASSERT_TRUE (known_gt (ph::make (-14, 0, 0), ch::make (13)));
+
+  /* Test known_gt (C, T).  */
+  ASSERT_EQ (known_gt (ch::make (4), ph::make (3, 5, -1)), N == 1);
+  ASSERT_EQ (known_gt (ch::make (41), ph::make (40, -10, 60)), N == 1);
+  ASSERT_TRUE (known_gt (ch::make (-15), ph::make (11, 0, 0)));
+
+  /* Test known_gt (T, T).  */
+  ASSERT_EQ (known_gt (ph::make (-2, 4, -2),
+                      ph::make (-3, -5, -1)), N == 1);
+  ASSERT_EQ (known_gt (ph::make (-2, -6, 0),
+                      ph::make (-3, 0, 100)), N <= 2);
+  ASSERT_TRUE (known_gt (ph::make (-2, 5, 1),
+                        ph::make (-3, 4, 0)));
+}
+
+/* Test known_ge for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_known_ge ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_ge (T, C).  */
+  ASSERT_TRUE (known_ge (ph::make (3, 5, -1), ch::make (2)));
+  ASSERT_TRUE (known_ge (ph::make (40, -10, 60), ch::make (15)));
+  ASSERT_TRUE (known_ge (ph::make (-18, 0, 0), ch::make (18)));
+  ASSERT_TRUE (known_ge (ph::make (-2, -2, -2), ch::make (-2)));
+
+  /* Test known_ge (C, T).  */
+  ASSERT_EQ (known_ge (ch::make (4), ph::make (3, 5, -1)), N == 1);
+  ASSERT_EQ (known_ge (ch::make (41), ph::make (40, -10, 60)), N == 1);
+  ASSERT_TRUE (known_ge (ch::make (-45), ph::make (40, 0, 0)));
+  ASSERT_EQ (known_ge (ch::make (-2), ph::make (-2, -2, -2)), N == 1);
+
+  /* Test known_ge (T, T).  */
+  ASSERT_EQ (known_ge (ph::make (-3, 4, -2),
+                      ph::make (-3, -5, -1)), N == 1);
+  ASSERT_EQ (known_ge (ph::make (-3, -6, 0),
+                      ph::make (-3, 0, 100)), N <= 2);
+  ASSERT_TRUE (known_ge (ph::make (-3, 5, 1),
+                        ph::make (-3, 4, 0)));
+}
+
+/* Test known_lt for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_known_lt ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_lt (T, C).  */
+  ASSERT_EQ (known_lt (ph::make (3, 5, -1), ch::make (4)), N == 1);
+  ASSERT_EQ (known_lt (ph::make (40, -10, 60), ch::make (41)), N == 1);
+  ASSERT_TRUE (known_lt (ph::make (11, 0, 0), ch::make (-15)));
+
+  /* Test known_lt (C, T).  */
+  ASSERT_TRUE (known_lt (ch::make (2), ph::make (3, 5, -1)));
+  ASSERT_TRUE (known_lt (ch::make (15), ph::make (40, -10, 60)));
+  ASSERT_TRUE (known_lt (ch::make (13), ph::make (-14, 0, 0)));
+
+  /* Test known_lt (T, T).  */
+  ASSERT_EQ (known_lt (ph::make (-3, -5, -1),
+                      ph::make (-2, 4, -2)), N == 1);
+  ASSERT_EQ (known_lt (ph::make (-3, 0, 100),
+                      ph::make (-2, -6, 0)), N <= 2);
+  ASSERT_TRUE (known_lt (ph::make (-3, 4, 0),
+                        ph::make (-2, 5, 1)));
+}
+
+/* Test known_le for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_known_le ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test known_le (T, C).  */
+  ASSERT_EQ (known_le (ph::make (3, 5, -1), ch::make (4)), N == 1);
+  ASSERT_EQ (known_le (ph::make (40, -10, 60), ch::make (41)), N == 1);
+  ASSERT_TRUE (known_le (ph::make (40, 0, 0), ch::make (-45)));
+  ASSERT_EQ (known_le (ph::make (-2, -2, -2), ch::make (-2)), N == 1);
+
+  /* Test known_le (C, T).  */
+  ASSERT_TRUE (known_le (ch::make (2), ph::make (3, 5, -1)));
+  ASSERT_TRUE (known_le (ch::make (15), ph::make (40, -10, 60)));
+  ASSERT_TRUE (known_le (ch::make (18), ph::make (-18, 0, 0)));
+  ASSERT_TRUE (known_le (ch::make (-2), ph::make (-2, -2, -2)));
+
+  /* Test known_le (T, T).  */
+  ASSERT_EQ (known_le (ph::make (-3, -5, -1),
+                      ph::make (-3, 4, -2)), N == 1);
+  ASSERT_EQ (known_le (ph::make (-3, 0, 100),
+                      ph::make (-3, -6, 0)), N <= 2);
+  ASSERT_TRUE (known_le (ph::make (-3, 4, 0),
+                        ph::make (-3, 5, 1)));
+}
+
+/* Test ordered_p for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_ordered_p ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test ordered_p (T, C).  */
+  ASSERT_EQ (ordered_p (ph::make (3, 5, -1), ch::make (4)), N == 1);
+  ASSERT_TRUE (ordered_p (ph::make (3, 5, -1), ch::make (3)));
+  ASSERT_TRUE (ordered_p (ph::make (3, 5, -1), ch::make (2)));
+  ASSERT_EQ (ordered_p (ph::make (40, -10, 60), ch::make (41)), N == 1);
+  ASSERT_TRUE (ordered_p (ph::make (40, -10, 60), ch::make (40)));
+  ASSERT_TRUE (ordered_p (ph::make (40, -10, 60), ch::make (39)));
+  ASSERT_TRUE (ordered_p (ph::make (4, -4, -4), ch::make (0)));
+  ASSERT_TRUE (ordered_p (ph::make (4, 0, -4), ch::make (0)));
+  ASSERT_TRUE (ordered_p (ph::make (4, 4, -4), ch::make (0)));
+  ASSERT_TRUE (ordered_p (ph::make (-4, 4, 4), ch::make (0)));
+  ASSERT_TRUE (ordered_p (ph::make (-4, 0, 4), ch::make (0)));
+  ASSERT_TRUE (ordered_p (ph::make (-4, -4, 4), ch::make (0)));
+
+  /* Test ordered_p (C, T).  */
+  ASSERT_EQ (ordered_p (ch::make (4), ph::make (3, 5, -1)), N == 1);
+  ASSERT_TRUE (ordered_p (ch::make (3), ph::make (3, 5, -1)));
+  ASSERT_TRUE (ordered_p (ch::make (2), ph::make (3, 5, -1)));
+  ASSERT_EQ (ordered_p (ch::make (41), ph::make (40, -10, 60)), N == 1);
+  ASSERT_TRUE (ordered_p (ch::make (40), ph::make (40, -10, 60)));
+  ASSERT_TRUE (ordered_p (ch::make (39), ph::make (40, -10, 60)));
+  ASSERT_TRUE (ordered_p (ch::make (0), ph::make (4, -4, -4)));
+  ASSERT_TRUE (ordered_p (ch::make (0), ph::make (4, 0, -4)));
+  ASSERT_TRUE (ordered_p (ch::make (0), ph::make (4, 4, -4)));
+  ASSERT_TRUE (ordered_p (ch::make (0), ph::make (-4, 4, 4)));
+  ASSERT_TRUE (ordered_p (ch::make (0), ph::make (-4, 0, 4)));
+  ASSERT_TRUE (ordered_p (ch::make (0), ph::make (-4, -4, 4)));
+}
+
+/* Test ordered_min for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_ordered_min ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test ordered_min (T, C).  */
+  ASSERT_KNOWN_EQ (ordered_min (ph::make (5, -12, -14), ch::make (5)),
+                  ch::make (5));
+
+  /* Test ordered_min (C, T).  */
+  ASSERT_KNOWN_EQ (ordered_min (ch::make (9), ph::make (9, -90, -77)),
+                  ch::make (9));
+
+  /* Test ordered_min (T, T).  */
+  ASSERT_KNOWN_EQ (ordered_min (ph::make (4, 9, 17), ph::make (4, -1, 17)),
+                  ph::make (4, 9, 17));
+}
+
+/* Test ordered_max for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_ordered_max ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test ordered_max (T, C).  */
+  ASSERT_KNOWN_EQ (ordered_max (ph::make (5, -12, -14), ch::make (5)),
+                  ph::make (5, -12, -14));
+
+  /* Test ordered_max (C, T).  */
+  ASSERT_KNOWN_EQ (ordered_max (ch::make (9), ph::make (9, -90, -77)),
+                  ph::make (9, -90, -77));
+
+  /* Test ordered_max (T, T).  */
+  ASSERT_KNOWN_EQ (ordered_max (ph::make (4, 9, 17), ph::make (4, -1, 17)),
+                  ph::make (4, -1, 17));
+}
+
+/* Test lower_bound for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_lower_bound ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test lower_bound (T, C).  */
+  ASSERT_KNOWN_EQ (lower_bound (ph::make (4, -1, 3), ch::make (5)),
+                  ch::make (4));
+  ASSERT_KNOWN_EQ (lower_bound (ph::make (6, 5, -14), ch::make (-11)),
+                  ch::make (6));
+
+  /* Test lower_bound (C, T).  */
+  ASSERT_KNOWN_EQ (lower_bound (ch::make (5), ph::make (4, -1, 3)),
+                  ch::make (4));
+  ASSERT_KNOWN_EQ (lower_bound (ch::make (-11), ph::make (6, 5, -14)),
+                  ch::make (6));
+
+  /* Test lower_bound (T, T).  */
+  ASSERT_KNOWN_EQ (lower_bound (ph::make (4, -1, 3), ph::make (5, 7, -2)),
+                  ph::make (4, 7, 3));
+  ASSERT_KNOWN_EQ (lower_bound (ph::make (6, 5, -14), ph::make (-11, 4, 3)),
+                  ph::make (6, 4, 3));
+}
+
+/* Test upper_bound for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_upper_bound ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test upper_bound (T, C).  */
+  ASSERT_KNOWN_EQ (upper_bound (ph::make (4, -1, 3), ch::make (5)),
+                  ph::make (5, -1, 3));
+  ASSERT_KNOWN_EQ (upper_bound (ph::make (6, 5, -14), ch::make (-11)),
+                  ph::make (-11, 5, -14));
+
+  /* Test upper_bound (C, T).  */
+  ASSERT_KNOWN_EQ (upper_bound (ch::make (5), ph::make (4, -1, 3)),
+                  ph::make (5, -1, 3));
+  ASSERT_KNOWN_EQ (upper_bound (ch::make (-11), ph::make (6, 5, -14)),
+                  ph::make (-11, 5, -14));
+
+  /* Test upper_bound (T, T).  */
+  ASSERT_KNOWN_EQ (upper_bound (ph::make (4, -1, 3), ph::make (5, 7, -2)),
+                  ph::make (5, -1, -2));
+  ASSERT_KNOWN_EQ (upper_bound (ph::make (6, 5, -14), ph::make (-11, 4, 3)),
+                  ph::make (-11, 5, -14));
+}
+
+/* Test maybe_in_range_p for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_maybe_in_range_p ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Unknown size for N == 1.  */
+  ASSERT_TRUE (maybe_in_range_p (ch::make (-1),
+                                ch::make (0),
+                                ph::make (-1, -1, -1)));
+  /* Unknown size for all N.  */
+  ASSERT_TRUE (maybe_in_range_p (ph::make (-1, -1, -1),
+                                ch::make (0),
+                                ch::make (-1)));
+  /* Unknown size for N == 1.  */
+  ASSERT_EQ (maybe_in_range_p (ph::make (-1, -1, -1),
+                              ch::make (0),
+                              ph::make (-1, -1, -1)), N == 1);
+  ASSERT_EQ (maybe_in_range_p (ch::make (-2),
+                              ch::make (0),
+                              ph::make (-2, -2, -2)), N >= 2);
+  ASSERT_FALSE (maybe_in_range_p (ph::make (-2, -2, -2),
+                                 ch::make (0),
+                                 ch::make (-2)));
+  ASSERT_FALSE (maybe_in_range_p (ph::make (-2, -2, -2),
+                                 ch::make (0),
+                                 ph::make (-2, -2, -2)));
+  ASSERT_TRUE (maybe_in_range_p (ph::make (-2, -2, -2),
+                                ch::make (1),
+                                ph::make (-2, -2, -2)));
+  ASSERT_TRUE (maybe_in_range_p (ph::make (-2, -2, -2),
+                                ch::make (1),
+                                ch::make (-2)));
+}
+
+/* Test known_in_range_p for unsigned C.  */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_unsigned_known_in_range_p ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  ASSERT_FALSE (known_in_range_p (ch::make (4),
+                                 ph::make (5, 1, 2),
+                                 ch::make (-2)));
+  ASSERT_TRUE (known_in_range_p (ph::make (6, 1, 2),
+                                ph::make (5, 1, 2),
+                                ch::make (-2)));
+  ASSERT_TRUE (known_in_range_p (ph::make (6, 1, 2),
+                                ph::make (5, 1, 2),
+                                ph::make (-2, -2, -2)));
+}
+
+/* Test things that work for poly_int-based types T, given that the
+   coefficient type C is a primitive integer type.  N is the number of
+   coefficients in C */
+
+template<unsigned int N, typename C, typename T>
+static void
+test_hwi ()
+{
+  typedef coeff_helper<C> ch;
+  typedef poly_helper<T> ph;
+
+  /* Test coeff_gcd.  */
+  ASSERT_EQ (coeff_gcd (ph::make (30, 45, 10)),
+            N == 1 ? 30 : N == 2 ? 15 : 5);
+  ASSERT_EQ (coeff_gcd (ph::make (0, 18, 21)),
+            N == 1 ? 0 : N == 2 ? 18 : 3);
+  ASSERT_EQ (coeff_gcd (ph::make (0, 0, 101)),
+            N <= 2 ? 0 : 101);
+  ASSERT_EQ (coeff_gcd (ph::make (21, 0, 28)),
+            N <= 2 ? 21 : 7);
+  ASSERT_EQ (coeff_gcd (ph::make (100, 175, 0)),
+            N == 1 ? 100 : 25);
+
+  /* Test common_multiple (T, C).  */
+  ASSERT_KNOWN_EQ (common_multiple (ph::make (8, 24, 16), 6),
+                  ph::make (24, 72, 48));
+  ASSERT_KNOWN_EQ (common_multiple (ph::make (30, 0, 0), 45),
+                  ch::make (90));
+  if (N >= 2)
+    ASSERT_KNOWN_EQ (common_multiple (ph::make (18, 15, 0), 12),
+                    ph::make (72, 60, 0));
+  if (N == 3)
+    ASSERT_KNOWN_EQ (common_multiple (ph::make (18, 15, 4), 12),
+                    ph::make (216, 180, 48));
+
+  /* Test common_multiple (C, T).  */
+  ASSERT_KNOWN_EQ (common_multiple (6, ph::make (8, 24, 16)),
+                  ph::make (24, 72, 48));
+  ASSERT_KNOWN_EQ (common_multiple (45, ph::make (30, 0, 0)),
+                  ch::make (90));
+  if (N >= 2)
+    ASSERT_KNOWN_EQ (common_multiple (12, ph::make (18, 15, 0)),
+                    ph::make (72, 60, 0));
+  if (N == 3)
+    ASSERT_KNOWN_EQ (common_multiple (12, ph::make (18, 15, 4)),
+                    ph::make (216, 180, 48));
+
+  /* Test force_common_multiple.  */
+  ASSERT_KNOWN_EQ (force_common_multiple (ph::make (30, 0, 0),
+                                         ph::make (25, 0, 0)),
+                  ph::make (150, 0, 0));
+  if (N >= 2)
+    {
+      ASSERT_KNOWN_EQ (force_common_multiple (ph::make (16, 24, 0),
+                                             ph::make (24, 36, 0)),
+                      ph::make (48, 72, 0));
+      ASSERT_KNOWN_EQ (force_common_multiple (ph::make (16, 24, 0),
+                                             ph::make (12, 0, 0)),
+                      ph::make (48, 72, 0));
+      ASSERT_KNOWN_EQ (force_common_multiple (ph::make (15, 0, 0),
+                                             ph::make (21, 9, 0)),
+                      ph::make (105, 45, 0));
+    }
+  if (N == 3)
+    {
+      ASSERT_KNOWN_EQ (force_common_multiple (ph::make (33, 99, 66),
+                                             ph::make (22, 66, 44)),
+                      ph::make (66, 198, 132));
+      ASSERT_KNOWN_EQ (force_common_multiple (ph::make (30, 0, 45),
+                                             ph::make (12, 0, 18)),
+                      ph::make (60, 0, 90));
+      ASSERT_KNOWN_EQ (force_common_multiple (ph::make (40, 0, 50),
+                                             ph::make (8, 0, 0)),
+                      ph::make (160, 0, 200));
+      ASSERT_KNOWN_EQ (force_common_multiple (ph::make (6, 0, 0),
+                                             ph::make (10, 0, 15)),
+                      ph::make (60, 0, 90));
+      ASSERT_KNOWN_EQ (force_common_multiple (ph::make (20, 40, 30),
+                                             ph::make (15, 0, 0)),
+                      ph::make (60, 120, 90));
+      ASSERT_KNOWN_EQ (force_common_multiple (ph::make (9, 0, 0),
+                                             ph::make (90, 81, 27)),
+                      ph::make (90, 81, 27));
+    }
+}
+
+/* Test poly_int<N, C>::to_shwi, using in-range source coefficient value
+   SRCV (equal to DESTV) and adding DELTA to get an out-of-range value.  */
+
+template<unsigned int N, typename C>
+static void
+test_to_shwi (const C &srcv, int delta, HOST_WIDE_INT destv)
+{
+  typedef poly_helper< poly_int<N, HOST_WIDE_INT> > ps64h;
+  typedef poly_int<N, C> T;
+  typedef poly_helper<T> ph;
+  poly_int<N, HOST_WIDE_INT> shwi;
+
+  /* Test in-range T::to_shwi.  */
+  ASSERT_TRUE (ph::make (srcv,
+                        srcv - delta,
+                        srcv - delta * 2).to_shwi (&shwi));
+  ASSERT_KNOWN_EQ (shwi, ps64h::make (destv,
+                                     destv - delta,
+                                     destv - delta * 2));
+
+  /* Test partially in-range T::to_shwi.  */
+  ASSERT_EQ (ph::make (srcv,
+                      srcv + delta,
+                      srcv + delta * 2).to_shwi (&shwi), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (shwi, destv);
+  ASSERT_EQ (ph::make (srcv - delta,
+                      srcv,
+                      srcv + delta).to_shwi (&shwi), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (shwi, ps64h::make (destv - delta,
+                                       destv,
+                                       destv /* ignored */));
+
+  /* Test fully out-of-range T::to_shwi.  */
+  ASSERT_FALSE (ph::make (srcv + delta, srcv, srcv).to_shwi (&shwi));
+}
+
+/* Test poly_int<N, C>::to_uhwi, using in-range source coefficient value
+   SRCV (equal to DESTV) and adding DELTA to get an out-of-range value.  */
+
+template<unsigned int N, typename C>
+static void
+test_to_uhwi (const C &srcv, int delta, unsigned HOST_WIDE_INT destv)
+{
+  typedef poly_helper< poly_int<N, unsigned HOST_WIDE_INT> > pu64h;
+  typedef poly_int<N, C> T;
+  typedef poly_helper<T> ph;
+  poly_int<N, unsigned HOST_WIDE_INT> uhwi;
+
+  /* Test in-range T::to_uhwi.  */
+  ASSERT_TRUE (ph::make (srcv,
+                        srcv - delta,
+                        srcv - delta * 2).to_uhwi (&uhwi));
+  ASSERT_KNOWN_EQ (uhwi, pu64h::make (destv,
+                                     destv - delta,
+                                     destv - delta * 2));
+
+  /* Test partially in-range T::to_uhwi.  */
+  ASSERT_EQ (ph::make (srcv,
+                      srcv + delta,
+                      srcv + delta * 2).to_uhwi (&uhwi), N == 1);
+  if (N == 1)
+    ASSERT_KNOWN_EQ (uhwi, destv);
+  ASSERT_EQ (ph::make (srcv - delta,
+                      srcv,
+                      srcv + delta).to_uhwi (&uhwi), N <= 2);
+  if (N <= 2)
+    ASSERT_KNOWN_EQ (uhwi, pu64h::make (destv - delta,
+                                       destv,
+                                       destv /* ignored */));
+
+  /* Test fully out-of-range T::to_uhwi.  */
+  ASSERT_FALSE (ph::make (srcv + delta, srcv, srcv).to_uhwi (&uhwi));
+}
+
+/* Test poly_int<N, C>::force_shwi and poly_int<N, C>::force_uhwi, given
+   that MASK66 has the low 66 bits set and the rest clear.  */
+
+template<unsigned int N, typename C>
+static void
+test_force_hwi (const C &mask66)
+{
+  typedef poly_helper< poly_int<N, HOST_WIDE_INT> > ps64h;
+  typedef poly_helper< poly_int<N, unsigned HOST_WIDE_INT> > pu64h;
+  typedef poly_int<N, C> T;
+  typedef poly_helper<T> ph;
+  poly_int<N, HOST_WIDE_INT> shwi;
+  poly_int<N, unsigned HOST_WIDE_INT> uhwi;
+
+  C mask65 = wi::arshift (mask66, 1);
+  C mask64 = wi::arshift (mask66, 2);
+  C mask63 = wi::arshift (mask66, 3);
+  C mask62 = wi::arshift (mask66, 4);
+  C mask61 = wi::arshift (mask66, 5);
+
+  /* Test force_shwi.  */
+  ASSERT_KNOWN_EQ (ph::make (mask66, mask65, mask64).force_shwi (),
+                  ps64h::make (HOST_WIDE_INT_M1,
+                               HOST_WIDE_INT_M1,
+                               HOST_WIDE_INT_M1));
+  ASSERT_KNOWN_EQ (ph::make (mask65, mask64, mask63).force_shwi (),
+                  ps64h::make (HOST_WIDE_INT_M1,
+                               HOST_WIDE_INT_M1,
+                               HOST_WIDE_INT_MAX));
+  ASSERT_KNOWN_EQ (ph::make (mask64, mask63, mask62).force_shwi (),
+                  ps64h::make (HOST_WIDE_INT_M1,
+                               HOST_WIDE_INT_MAX,
+                               HOST_WIDE_INT_MAX / 2));
+  ASSERT_KNOWN_EQ (ph::make (mask63, mask62, mask61).force_shwi (),
+                  ps64h::make (HOST_WIDE_INT_MAX,
+                               HOST_WIDE_INT_MAX / 2,
+                               HOST_WIDE_INT_MAX / 4));
+
+  /* Test force_uhwi.  */
+  ASSERT_KNOWN_EQ (ph::make (mask66, mask65, mask64).force_uhwi (),
+                  pu64h::make (HOST_WIDE_INT_M1U,
+                               HOST_WIDE_INT_M1U,
+                               HOST_WIDE_INT_M1U));
+  ASSERT_KNOWN_EQ (ph::make (mask65, mask64, mask63).force_uhwi (),
+                  pu64h::make (HOST_WIDE_INT_M1U,
+                               HOST_WIDE_INT_M1U,
+                               HOST_WIDE_INT_M1U >> 1));
+  ASSERT_KNOWN_EQ (ph::make (mask64, mask63, mask62).force_uhwi (),
+                  pu64h::make (HOST_WIDE_INT_M1U,
+                               HOST_WIDE_INT_M1U >> 1,
+                               HOST_WIDE_INT_M1U >> 2));
+  ASSERT_KNOWN_EQ (ph::make (mask63, mask62, mask61).force_uhwi (),
+                  pu64h::make (HOST_WIDE_INT_M1U >> 1,
+                               HOST_WIDE_INT_M1U >> 2,
+                               HOST_WIDE_INT_M1U >> 3));
+}
+
+/* Test poly_int<N, wide_int>::from.  */
+
+template<unsigned int N>
+static void
+test_wide_int_from ()
+{
+  typedef poly_helper< poly_int<N, unsigned char> > pu8h;
+  typedef poly_int<N, wide_int> T;
+  typedef poly_helper<T> ph;
+
+  /* Test narrowing cases of T::from.  */
+  T p_8_3_1 = ph::make (wi::uhwi (8, 3),
+                       wi::uhwi (3, 3),
+                       wi::uhwi (1, 3));
+  ASSERT_KNOWN_EQ (T::from (pu8h::make (0xf8,0x23,0x81), 3, SIGNED),
+                  p_8_3_1);
+  ASSERT_KNOWN_EQ (T::from (pu8h::make (0xf8,0x23,0x81), 3, UNSIGNED),
+                  p_8_3_1);
+
+  /* Test equal-sized cases of T::from.  */
+  T p_f8_23_81 = ph::make (wi::uhwi (0xf8, 8),
+                          wi::uhwi (0x23, 8),
+                          wi::uhwi (0x81, 8));
+  ASSERT_KNOWN_EQ (T::from (pu8h::make (0xf8,0x23,0x81), 8, SIGNED),
+                  p_f8_23_81);
+  ASSERT_KNOWN_EQ (T::from (pu8h::make (0xf8,0x23,0x81), 8, UNSIGNED),
+                  p_f8_23_81);
+
+  /* Test widening cases of T::from.  */
+  T p_fff8_0023_ff81 = ph::make (wi::uhwi (0xfff8, 16),
+                                wi::uhwi (0x0023, 16),
+                                wi::uhwi (0xff81, 16));
+  ASSERT_KNOWN_EQ (T::from (pu8h::make (0xf8,0x23,0x81), 16, SIGNED),
+                  p_fff8_0023_ff81);
+  T p_00f8_0023_0081 = ph::make (wi::uhwi (0xf8, 16),
+                                wi::uhwi (0x23, 16),
+                                wi::uhwi (0x81, 16));
+  ASSERT_KNOWN_EQ (T::from (pu8h::make (0xf8,0x23,0x81), 16, UNSIGNED),
+                  p_00f8_0023_0081);
+}
+
+/* Test wi::sext for poly_int<N, wide_int>.  */
+
+template<unsigned int N>
+static void
+test_wide_int_sext ()
+{
+  typedef poly_int<N, wide_int> T;
+  typedef poly_helper<T> ph;
+
+  ASSERT_KNOWN_EQ (wi::sext (ph::make (wi::shwi (16, 12),
+                                      wi::shwi (63, 12),
+                                      wi::shwi (14, 12)), 5),
+                  ph::make (wi::shwi (-16, 12),
+                            wi::shwi (-1, 12),
+                            wi::shwi (14, 12)));
+  ASSERT_KNOWN_EQ (wi::sext (ph::make (wi::shwi (1024, 12),
+                                      wi::shwi (1023, 12),
+                                      wi::shwi (1200, 12)), 11),
+                  ph::make (wi::shwi (-1024, 12),
+                            wi::shwi (1023, 12),
+                            wi::shwi (-848, 12)));
+}
+
+/* Test wi::zext for poly_int<N, wide_int>.  */
+
+template<unsigned int N>
+static void
+test_wide_int_zext ()
+{
+  typedef poly_int<N, wide_int> T;
+  typedef poly_helper<T> ph;
+
+  ASSERT_KNOWN_EQ (wi::zext (ph::make (wi::uhwi (16, 12),
+                                      wi::uhwi (63, 12),
+                                      wi::uhwi (14, 12)), 5),
+                  ph::make (wi::uhwi (16, 12),
+                            wi::uhwi (31, 12),
+                            wi::uhwi (14, 12)));
+  ASSERT_KNOWN_EQ (wi::zext (ph::make (wi::uhwi (1024, 12),
+                                      wi::uhwi (1023, 12),
+                                      wi::uhwi (3248, 12)), 11),
+                  ph::make (wi::uhwi (1024, 12),
+                            wi::uhwi (1023, 12),
+                            wi::uhwi (1200, 12)));
+}
+
+/* Test wi::add for poly_int<N, wide_int>.  */
+
+template<unsigned int N>
+static void
+test_wide_int_add ()
+{
+  typedef poly_int<N, wide_int> T;
+  typedef poly_helper<T> ph;
+
+  bool overflow;
+  ASSERT_KNOWN_EQ (wi::add (ph::make (wi::uhwi (15, 4),
+                                     wi::uhwi (4, 4),
+                                     wi::uhwi (2, 4)),
+                           ph::make (wi::uhwi (1, 4),
+                                     wi::uhwi (0, 4),
+                                     wi::uhwi (0, 4)),
+                           UNSIGNED, &overflow),
+                  ph::make (wi::uhwi (0, 4),
+                            wi::uhwi (4, 4),
+                            wi::uhwi (2, 4)));
+  ASSERT_TRUE (overflow);
+  ASSERT_KNOWN_EQ (wi::add (ph::make (wi::uhwi (30, 5),
+                                     wi::uhwi (6, 5),
+                                     wi::uhwi (11, 5)),
+                           ph::make (wi::uhwi (1, 5),
+                                     wi::uhwi (26, 5),
+                                     wi::uhwi (19, 5)),
+                           UNSIGNED, &overflow),
+                  ph::make (wi::uhwi (31, 5),
+                            wi::uhwi (0, 5),
+                            wi::uhwi (30, 5)));
+  ASSERT_EQ (overflow, N >= 2);
+  ASSERT_KNOWN_EQ (wi::add (ph::make (wi::uhwi (1, 6),
+                                     wi::uhwi (63, 6),
+                                     wi::uhwi (50, 6)),
+                           ph::make (wi::uhwi (61, 6),
+                                     wi::uhwi (0, 6),
+                                     wi::uhwi (50, 6)),
+                           UNSIGNED, &overflow),
+                  ph::make (wi::uhwi (62, 6),
+                            wi::uhwi (63, 6),
+                            wi::uhwi (36, 6)));
+  ASSERT_EQ (overflow, N == 3);
+
+  ASSERT_KNOWN_EQ (wi::add (ph::make (wi::shwi (7, 4),
+                                     wi::shwi (7, 4),
+                                     wi::shwi (-8, 4)),
+                           ph::make (wi::shwi (1, 4),
+                                     wi::shwi (0, 4),
+                                     wi::shwi (0, 4)),
+                           SIGNED, &overflow),
+                  ph::make (wi::shwi (-8, 4),
+                            wi::shwi (7, 4),
+                            wi::shwi (-8, 4)));
+  ASSERT_TRUE (overflow);
+  ASSERT_KNOWN_EQ (wi::add (ph::make (wi::shwi (-1, 5),
+                                     wi::shwi (6, 5),
+                                     wi::shwi (11, 5)),
+                           ph::make (wi::shwi (15, 5),
+                                     wi::shwi (11, 5),
+                                     wi::shwi (-15, 5)),
+                           SIGNED, &overflow),
+                  ph::make (wi::shwi (14, 5),
+                            wi::shwi (-15, 5),
+                            wi::shwi (-4, 5)));
+  ASSERT_EQ (overflow, N >= 2);
+  ASSERT_KNOWN_EQ (wi::add (ph::make (wi::shwi (4, 6),
+                                     wi::shwi (0, 6),
+                                     wi::shwi (-1, 6)),
+                           ph::make (wi::shwi (-32, 6),
+                                     wi::shwi (-32, 6),
+                                     wi::shwi (-32, 6)),
+                           SIGNED, &overflow),
+                  ph::make (wi::shwi (-28, 6),
+                            wi::shwi (-32, 6),
+                            wi::shwi (31, 6)));
+  ASSERT_EQ (overflow, N == 3);
+}
+
+/* Test wi::sub for poly_int<N, wide_int>.  */
+
+template<unsigned int N>
+static void
+test_wide_int_sub ()
+{
+  typedef poly_int<N, wide_int> T;
+  typedef poly_helper<T> ph;
+
+  bool overflow;
+  ASSERT_KNOWN_EQ (wi::sub (ph::make (wi::uhwi (0, 4),
+                                     wi::uhwi (4, 4),
+                                     wi::uhwi (2, 4)),
+                           ph::make (wi::uhwi (1, 4),
+                                     wi::uhwi (0, 4),
+                                     wi::uhwi (0, 4)),
+                           UNSIGNED, &overflow),
+                  ph::make (wi::uhwi (15, 4),
+                            wi::uhwi (4, 4),
+                            wi::uhwi (2, 4)));
+  ASSERT_TRUE (overflow);
+  ASSERT_KNOWN_EQ (wi::sub (ph::make (wi::uhwi (30, 5),
+                                     wi::uhwi (29, 5),
+                                     wi::uhwi (11, 5)),
+                           ph::make (wi::uhwi (1, 5),
+                                     wi::uhwi (31, 5),
+                                     wi::uhwi (9, 5)),
+                           UNSIGNED, &overflow),
+                  ph::make (wi::uhwi (29, 5),
+                            wi::uhwi (30, 5),
+                            wi::uhwi (2, 5)));
+  ASSERT_EQ (overflow, N >= 2);
+  ASSERT_KNOWN_EQ (wi::sub (ph::make (wi::uhwi (0, 6),
+                                     wi::uhwi (63, 6),
+                                     wi::uhwi (0, 6)),
+                           ph::make (wi::uhwi (0, 6),
+                                     wi::uhwi (0, 6),
+                                     wi::uhwi (52, 6)),
+                           UNSIGNED, &overflow),
+                  ph::make (wi::uhwi (0, 6),
+                            wi::uhwi (63, 6),
+                            wi::uhwi (12, 6)));
+  ASSERT_EQ (overflow, N == 3);
+
+  ASSERT_KNOWN_EQ (wi::sub (ph::make (wi::shwi (-8, 4),
+                                     wi::shwi (5, 4),
+                                     wi::shwi (-7, 4)),
+                           ph::make (wi::shwi (1, 4),
+                                     wi::shwi (0, 4),
+                                     wi::shwi (0, 4)),
+                           SIGNED, &overflow),
+                  ph::make (wi::shwi (7, 4),
+                            wi::shwi (5, 4),
+                            wi::shwi (-7, 4)));
+  ASSERT_TRUE (overflow);
+  ASSERT_KNOWN_EQ (wi::sub (ph::make (wi::shwi (-1, 5),
+                                     wi::shwi (-7, 5),
+                                     wi::shwi (0, 5)),
+                           ph::make (wi::shwi (15, 5),
+                                     wi::shwi (11, 5),
+                                     wi::shwi (-15, 5)),
+                           SIGNED, &overflow),
+                  ph::make (wi::shwi (-16, 5),
+                            wi::shwi (14, 5),
+                            wi::shwi (15, 5)));
+  ASSERT_EQ (overflow, N >= 2);
+  ASSERT_KNOWN_EQ (wi::sub (ph::make (wi::shwi (-32, 6),
+                                     wi::shwi (-1, 6),
+                                     wi::shwi (0, 6)),
+                           ph::make (wi::shwi (-32, 6),
+                                     wi::shwi (-32, 6),
+                                     wi::shwi (-32, 6)),
+                           SIGNED, &overflow),
+                  ph::make (wi::shwi (0, 6),
+                            wi::shwi (31, 6),
+                            wi::shwi (-32, 6)));
+  ASSERT_EQ (overflow, N == 3);
+}
+
+/* Test wi::mul for poly_int<N, wide_int>.  */
+
+template<unsigned int N>
+static void
+test_wide_int_mul ()
+{
+  typedef poly_int<N, wide_int> T;
+  typedef poly_helper<T> ph;
+
+  bool overflow;
+  ASSERT_KNOWN_EQ (wi::mul (ph::make (wi::uhwi (4, 4),
+                                     wi::uhwi (3, 4),
+                                     wi::uhwi (2, 4)), 4,
+                           UNSIGNED, &overflow),
+                  ph::make (wi::uhwi (0, 4),
+                            wi::uhwi (12, 4),
+                            wi::uhwi (8, 4)));
+  ASSERT_TRUE (overflow);
+  ASSERT_KNOWN_EQ (wi::mul (ph::make (wi::uhwi (15, 5),
+                                     wi::uhwi (31, 5),
+                                     wi::uhwi (7, 5)), 2,
+                           UNSIGNED, &overflow),
+                  ph::make (wi::uhwi (30, 5),
+                            wi::uhwi (30, 5),
+                            wi::uhwi (14, 5)));
+  ASSERT_EQ (overflow, N >= 2);
+  ASSERT_KNOWN_EQ (wi::mul (ph::make (wi::uhwi (1, 6),
+                                     wi::uhwi (0, 6),
+                                     wi::uhwi (2, 6)), 63,
+                           UNSIGNED, &overflow),
+                  ph::make (wi::uhwi (63, 6),
+                            wi::uhwi (0, 6),
+                            wi::uhwi (62, 6)));
+  ASSERT_EQ (overflow, N == 3);
+
+  ASSERT_KNOWN_EQ (wi::mul (ph::make (wi::shwi (-1, 4),
+                                     wi::shwi (1, 4),
+                                     wi::shwi (0, 4)), -8,
+                           SIGNED, &overflow),
+                  ph::make (wi::shwi (-8, 4),
+                            wi::shwi (-8, 4),
+                            wi::shwi (0, 4)));
+  ASSERT_TRUE (overflow);
+  ASSERT_KNOWN_EQ (wi::mul (ph::make (wi::shwi (2, 5),
+                                     wi::shwi (-3, 5),
+                                     wi::shwi (1, 5)), 6,
+                           SIGNED, &overflow),
+                  ph::make (wi::shwi (12, 5),
+                            wi::shwi (14, 5),
+                            wi::shwi (6, 5)));
+  ASSERT_EQ (overflow, N >= 2);
+  ASSERT_KNOWN_EQ (wi::mul (ph::make (wi::shwi (5, 6),
+                                     wi::shwi (-6, 6),
+                                     wi::shwi (7, 6)), -5,
+                           SIGNED, &overflow),
+                  ph::make (wi::shwi (-25, 6),
+                            wi::shwi (30, 6),
+                            wi::shwi (29, 6)));
+  ASSERT_EQ (overflow, N == 3);
+}
+
+/* Test wi::neg for poly_int<N, wide_int>.  */
+
+template<unsigned int N>
+static void
+test_wide_int_neg ()
+{
+  typedef poly_int<N, wide_int> T;
+  typedef poly_helper<T> ph;
+
+  bool overflow;
+  ASSERT_KNOWN_EQ (wi::neg (ph::make (wi::shwi (-8, 4),
+                                     wi::shwi (7, 4),
+                                     wi::shwi (-7, 4)), &overflow),
+                  ph::make (wi::shwi (-8, 4),
+                            wi::shwi (-7, 4),
+                            wi::shwi (7, 4)));
+  ASSERT_TRUE (overflow);
+  ASSERT_KNOWN_EQ (wi::neg (ph::make (wi::shwi (-15, 5),
+                                     wi::shwi (-16, 5),
+                                     wi::shwi (15, 5)), &overflow),
+                  ph::make (wi::shwi (15, 5),
+                            wi::shwi (-16, 5),
+                            wi::shwi (-15, 5)));
+  ASSERT_EQ (overflow, N >= 2);
+  ASSERT_KNOWN_EQ (wi::neg (ph::make (wi::shwi (-28, 6),
+                                     wi::shwi (30, 6),
+                                     wi::shwi (-32, 6)), &overflow),
+                  ph::make (wi::shwi (28, 6),
+                            wi::shwi (-30, 6),
+                            wi::shwi (-32, 6)));
+  ASSERT_EQ (overflow, N == 3);
+}
+
+/* Test poly_int<N, C> for things that only make sense when C is an
+   offset_int or widest_int.  */
+
+template<unsigned int N, typename C>
+static void
+test_fixed_int (void)
+{
+  typedef poly_helper< poly_int<N, int> > pih;
+  typedef poly_int<N, C> T;
+  typedef poly_helper<T> ph;
+
+  /* Test signed case.  */
+  ASSERT_KNOWN_EQ (T::from (pih::make (-100, 200, -300), SIGNED),
+                  ph::make (-100, 200, -300));
+  ASSERT_MAYBE_NE (T::from (pih::make (-100, 200, -300), SIGNED),
+                  ph::make (-100U, 200U, -300U));
+
+  /* Test unsigned case.  */
+  ASSERT_MAYBE_NE (T::from (pih::make (-100, 200, -300), UNSIGNED),
+                  ph::make (-100, 200, -300));
+  ASSERT_KNOWN_EQ (T::from (pih::make (-100, 200, -300), UNSIGNED),
+                  ph::make (-100U, 200U, -300U));
+
+  C one = 1;
+  test_to_shwi<N> (-(one << 63), -1, HOST_WIDE_INT_MIN);
+  test_to_shwi<N> ((one << 63) - 1, 1, HOST_WIDE_INT_MAX);
+  test_to_uhwi<N> (C (0), -1, 0U);
+  test_to_uhwi<N> ((one << 64) - 1, 1, HOST_WIDE_INT_M1U);
+
+  /* Test force_shwi and force_uhwi.  */
+  test_force_hwi<N> ((one << 66) - 1);
+}
+
+/* Test type promotions.  */
+
+template<unsigned int N>
+static void
+test_type_promotions ()
+{
+  typedef poly_helper< poly_int<N, unsigned short> > pu16h;
+  typedef poly_helper< poly_int<N, HOST_WIDE_INT> > ps64h;
+  HOST_WIDE_INT mask32 = ~0U;
+
+  /* Test that + on unsigned short promotes to HOST_WIDE_INT.  */
+  ASSERT_KNOWN_EQ (pu16h::make (0xffff, 0xfffe, 0xfffd) + 16,
+                  ps64h::make (0x1000f, 0xfffe, 0xfffd));
+  ASSERT_KNOWN_EQ (32 + pu16h::make (0xffff, 0xfffe, 0xfffd),
+                  ps64h::make (0x1001f, 0xfffe, 0xfffd));
+  ASSERT_KNOWN_EQ (pu16h::make (0xffff, 0xfffe, 0xfffd)
+                  + pu16h::make (4, 10, 17),
+                  ps64h::make (0x10003, 0x10008, 0x1000e));
+
+  /* Test that - on unsigned short promotes to HOST_WIDE_INT.  */
+  ASSERT_KNOWN_EQ (pu16h::make (1, 2, 3) - ~0U,
+                  ps64h::make (-mask32 + 1, 2, 3));
+  ASSERT_KNOWN_EQ (INT_MIN - pu16h::make (4, 5, 6),
+                  ps64h::make ((HOST_WIDE_INT) INT_MIN - 4, -5, -6));
+  ASSERT_KNOWN_EQ (pu16h::make (1, 2, 3) - pu16h::make (100, 200, 300),
+                  ps64h::make (-99, -198, -297));
+
+  /* Same for unary -.  */
+  ASSERT_KNOWN_EQ (-pu16h::make (0x8000, 0x9000, 0xa000),
+                  ps64h::make (-0x8000, -0x9000, -0xa000));
+  ASSERT_MAYBE_NE (-pu16h::make (0x8000, 0x9000, 0xa000),
+                  ps64h::make (0x8000, 0x9000, 0xa000));
+
+  /* Test that * on unsigned short promotes to HOST_WIDE_INT.  */
+  ASSERT_KNOWN_EQ (pu16h::make (10, 14, 17) * ~0U,
+                  ps64h::make (10 * mask32, 14 * mask32, 17 * mask32));
+  ASSERT_KNOWN_EQ (-400000 * pu16h::make (10, 14, 17),
+                  ps64h::make (-4000000, -5600000, -6800000));
+
+  /* Test that << on unsigned short promotes to HOST_WIDE_INT.  */
+  ASSERT_KNOWN_EQ (pu16h::make (4, 5, 6) << 50,
+                  ps64h::make ((HOST_WIDE_INT) 4 << 50,
+                               (HOST_WIDE_INT) 5 << 50,
+                               (HOST_WIDE_INT) 6 << 50));
+
+  /* Test that can_align_up doesn't truncate to the type of the alignment.  */
+  poly_int<N, HOST_WIDE_INT> aligned;
+  HOST_WIDE_INT a = (HOST_WIDE_INT_1 << 50);
+  HOST_WIDE_INT b = (HOST_WIDE_INT_1 << 51);
+  HOST_WIDE_INT c = (HOST_WIDE_INT_1 << 52);
+  ASSERT_TRUE (can_align_up (ps64h::make (a - 31, b, c), 16U, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ps64h::make (a - 16, b, c));
+
+  /* Likewise for can_align_down.  */
+  ASSERT_TRUE (can_align_down (ps64h::make (a - 31, b, c), 16U, &aligned));
+  ASSERT_KNOWN_EQ (aligned, ps64h::make (a - 32, b, c));
+
+  /* Same for the force_* routines.  */
+  ASSERT_KNOWN_EQ (force_align_up (ps64h::make (a - 31, b, c), 16U),
+                  ps64h::make (a - 16, b, c));
+  ASSERT_KNOWN_EQ (force_align_down (ps64h::make (a - 31, b, c), 16U),
+                  ps64h::make (a - 32, b, c));
+
+  /* Same for the aligned_*_bound routines.  */
+  ASSERT_KNOWN_EQ (aligned_upper_bound (ps64h::make (a - 31, b - 33, c - 55),
+                                       16U),
+                  ps64h::make (a - 16, b - 32, c - 48));
+  ASSERT_KNOWN_EQ (aligned_lower_bound (ps64h::make (a - 31, b - 33, c - 55),
+                                       16U),
+                  ps64h::make (a - 32, b - 48, c - 64));
+}
+
+/* Test endpoint_representable_p.  */
+
+static void
+test_endpoint_representable (void)
+{
+  /* True because the size is unknown.  */
+  ASSERT_TRUE (endpoint_representable_p ((unsigned char) 0x80,
+                                        (unsigned char) 0xff));
+  ASSERT_FALSE (endpoint_representable_p ((unsigned char) 0x80,
+                                         (unsigned char) 0xfe));
+  ASSERT_FALSE (endpoint_representable_p ((unsigned char) 0x80,
+                                         (unsigned char) 0x80));
+  ASSERT_TRUE (endpoint_representable_p ((unsigned char) 0x80,
+                                        (unsigned char) 0x7f));
+  ASSERT_FALSE (endpoint_representable_p ((unsigned char) 0x11,
+                                         (unsigned char) 0xef));
+  ASSERT_TRUE (endpoint_representable_p ((unsigned char) 0x11,
+                                        (unsigned char) 0xee));
+
+  /* True because the size is unknown.  */
+  ASSERT_TRUE (endpoint_representable_p (INT_MAX, -1));
+  ASSERT_FALSE (endpoint_representable_p (INT_MAX - 100, INT_MAX));
+  ASSERT_FALSE (endpoint_representable_p (INT_MAX - 100, 101));
+  ASSERT_TRUE (endpoint_representable_p (INT_MAX - 100, 100));
+  ASSERT_TRUE (endpoint_representable_p (0, INT_MAX));
+  ASSERT_TRUE (endpoint_representable_p (INT_MIN, INT_MAX));
+
+  /* True because the size is unknown.  */
+  ASSERT_TRUE (endpoint_representable_p (UINT_MAX, -1U));
+  ASSERT_FALSE (endpoint_representable_p (UINT_MAX - 400, UINT_MAX - 1));
+  ASSERT_FALSE (endpoint_representable_p (UINT_MAX - 400, 401U));
+  ASSERT_TRUE (endpoint_representable_p (UINT_MAX - 400, 400U));
+}
+
+/* Test wi::shwi with N coefficients.  */
+
+template<unsigned int N>
+static void
+test_shwi ()
+{
+  typedef poly_int<N, wi::hwi_with_prec> T;
+  typedef poly_helper<T> ph;
+
+  poly_int<N, wide_int> mult;
+  mult = ph::make (wi::shwi (80, 16),
+                  wi::shwi (-10, 16),
+                  wi::shwi (70, 16)) * 3;
+  ASSERT_KNOWN_EQ (mult, ph::make (wi::shwi (240, 16),
+                                  wi::shwi (-30, 16),
+                                  wi::shwi (210, 16)));
+}
+
+/* Test wi::uhwi with N coefficients.  */
+
+template<unsigned int N>
+static void
+test_uhwi ()
+{
+  typedef poly_int<N, wi::hwi_with_prec> T;
+  typedef poly_helper<T> ph;
+
+  poly_int<N, wide_int> mult;
+  mult = ph::make (wi::uhwi (80, 16),
+                  wi::uhwi (-10, 16),
+                  wi::uhwi (70, 16)) * 3;
+  ASSERT_KNOWN_EQ (mult, ph::make (wi::uhwi (240, 16),
+                                  wi::uhwi (-30, 16),
+                                  wi::uhwi (210, 16)));
+}
+
+/* Test known_size_p for non-polynomial T.  */
+
+template<typename T>
+static void
+test_nonpoly_known_size_p ()
+{
+  ASSERT_TRUE (known_size_p (T (0)));
+  ASSERT_TRUE (known_size_p (T (1)));
+  ASSERT_TRUE (known_size_p (T (2)));
+  ASSERT_FALSE (known_size_p (T (-1)));
+}
+
+/* Test poly-int.h operations on non-polynomial type T.  */
+
+template<typename T>
+static void
+test_nonpoly_type ()
+{
+  test_nonpoly_known_size_p<T> ();
+}
+
+/* Test poly-int.h operations on non-polynomial values.  */
+
+static void
+test_nonpoly ()
+{
+  test_nonpoly_type<unsigned char> ();
+  test_nonpoly_type<unsigned short> ();
+  test_nonpoly_type<int> ();
+  test_nonpoly_type<unsigned int> ();
+  test_nonpoly_type<HOST_WIDE_INT> ();
+  test_nonpoly_type<unsigned HOST_WIDE_INT> ();
+  test_nonpoly_type<offset_int> ();
+  test_nonpoly_type<widest_int> ();
+}
+
+/* Test things that work for all poly_int-based types T, given that T
+   has N coefficients of type C.  RC is the type to which C promotes
+   after an operator.  */
+
+template<unsigned int N, typename C, typename RC, typename T>
+static void
+test_general ()
+{
+  test_poly_int_traits<N, C, T> ();
+  test_constants<N, C, T> ();
+  test_plus_equals<N, C, T> ();
+  test_minus_equals<N, C, T> ();
+  test_times_equals<N, C, T> ();
+  test_shl_equals<N, C, T> ();
+  test_is_constant<N, C, T> ();
+  test_to_constant<N, C, T> ();
+  test_addition<N, C, T> ();
+  test_subtraction<N, C, RC, T> ();
+  test_negation<N, C, RC, T> ();
+  test_multiplication<N, C, T> ();
+  test_shift_left<N, C, T> ();
+  test_maybe_ne<N, C, T> ();
+  test_known_eq<N, C, T> ();
+  test_can_align_p<N, C, T> ();
+  test_can_align_up<N, C, T> ();
+  test_can_align_down<N, C, T> ();
+  test_known_equal_after_align_up<N, C, T> ();
+  test_known_equal_after_align_down<N, C, T> ();
+  test_force_align_up<N, C, T> ();
+  test_force_align_down<N, C, T> ();
+  test_aligned_lower_bound<N, C, T> ();
+  test_aligned_upper_bound<N, C, T> ();
+  test_known_misalignment<N, C, T> ();
+  test_force_get_misalignment<N, C, T> ();
+  test_known_alignment<N, C, T> ();
+  test_can_ior_p<N, C, T> ();
+  test_known_size_p<N, C, T> ();
+}
+
+/* Test things that work for poly_int<2, C>, given that C is signed.  */
+
+template<typename C>
+static void
+test_ordered_2 ()
+{
+  test_maybe_eq_2<C> ();
+  test_known_ne_2<C> ();
+}
+
+/* Test things that work for poly_int-based types T, given that the
+   coefficient type C supports all the normal C operators.  N is the
+   number of coefficients in C and RC is the type to which C promotes
+   after an operator.  */
+
+template<unsigned int N, typename C, typename RC, typename T>
+static void
+test_ordered ()
+{
+  test_general<N, C, RC, T> ();
+  test_maybe_le<N, C, T> ();
+  test_maybe_lt<N, C, T> ();
+  test_maybe_ge<N, C, T> ();
+  test_maybe_gt<N, C, T> ();
+  test_known_gt<N, C, T> ();
+  test_known_ge<N, C, T> ();
+  test_known_lt<N, C, T> ();
+  test_known_le<N, C, T> ();
+  test_ordered_p<N, C, T> ();
+  test_ordered_min<N, C, T> ();
+  test_ordered_max<N, C, T> ();
+  test_constant_lower_bound<N, C, T> ();
+  test_lower_bound<N, C, T> ();
+  test_upper_bound<N, C, T> ();
+  test_compare_sizes_for_sort<N, C, T> ();
+  test_force_align_up_and_div<N, C, T> ();
+  test_force_align_down_and_div<N, C, T> ();
+  test_constant_multiple_p<N, C, T> ();
+  test_multiple_p<N, C, T> ();
+  test_multiple_p_with_result<N, C, T> ();
+  test_exact_div<N, C, T> ();
+  test_can_div_trunc_p_const<N, C, T> ();
+  test_can_div_trunc_p_poly<N, C, T> ();
+  test_can_div_away_from_zero_p<N, C, T> ();
+  test_maybe_in_range_p<N, C, T> ();
+  test_known_in_range_p<N, C, T> ();
+  test_ranges_maybe_overlap_p<N, C, T> ();
+  test_ranges_known_overlap_p<N, C, T> ();
+  test_known_subrange_p<N, C, T> ();
+  test_coeffs_in_range_p<N, C, T> ();
+}
+
+/* Test things that work for poly_int<2, C>, given that C is signed.  */
+
+template<typename C>
+static void
+test_signed_2 ()
+{
+  test_ordered_2<C> ();
+  test_signed_maybe_eq_2<C> ();
+  test_signed_known_ne_2<C> ();
+}
+
+/* Test things that work for poly_int-based types T, given that the
+   coefficient type C is signed.  N is the number of coefficients in C
+   and RC is the type to which C promotes after an operator.  */
+
+template<unsigned int N, typename C, typename RC, typename T>
+static void
+test_signed ()
+{
+  test_ordered<N, C, RC, T> ();
+  test_signed_negation<N, C, RC, T> ();
+  test_signed_maybe_le<N, C, T> ();
+  test_signed_maybe_lt<N, C, T> ();
+  test_signed_maybe_ge<N, C, T> ();
+  test_signed_maybe_gt<N, C, T> ();
+  test_signed_known_gt<N, C, T> ();
+  test_signed_known_ge<N, C, T> ();
+  test_signed_known_lt<N, C, T> ();
+  test_signed_known_le<N, C, T> ();
+  test_signed_ordered_p<N, C, T> ();
+  test_signed_ordered_min<N, C, T> ();
+  test_signed_ordered_max<N, C, T> ();
+  test_signed_lower_bound<N, C, T> ();
+  test_signed_upper_bound<N, C, T> ();
+  test_signed_constant_multiple_p<N, C, T> ();
+  test_signed_multiple_p<N, C, T> ();
+  test_signed_multiple_p_with_result<N ,C, T> ();
+  test_signed_exact_div<N, C, T> ();
+  test_signed_can_div_trunc_p_const<N, C, T> ();
+  test_signed_can_div_trunc_p_poly<N, C, T> ();
+  test_signed_can_div_away_from_zero_p<N, C, T> ();
+  test_signed_maybe_in_range_p<N, C, T> ();
+}
+
+/* Test things that work for poly_int-based types T, given that the
+   coefficient type C is unsigned.  N is the number of coefficients in C
+   and RC is the type to which C promotes after an operator.  */
+
+template<unsigned int N, typename C, typename RC, typename T>
+static void
+test_unsigned ()
+{
+  test_ordered<N, C, RC, T> ();
+  test_unsigned_maybe_le<N, C, T> ();
+  test_unsigned_maybe_lt<N, C, T> ();
+  test_unsigned_maybe_ge<N, C, T> ();
+  test_unsigned_maybe_gt<N, C, T> ();
+  test_unsigned_known_gt<N, C, T> ();
+  test_unsigned_known_ge<N, C, T> ();
+  test_unsigned_known_lt<N, C, T> ();
+  test_unsigned_known_le<N, C, T> ();
+  test_unsigned_ordered_p<N, C, T> ();
+  test_unsigned_ordered_min<N, C, T> ();
+  test_unsigned_ordered_max<N, C, T> ();
+  test_unsigned_lower_bound<N, C, T> ();
+  test_unsigned_upper_bound<N, C, T> ();
+  test_unsigned_maybe_in_range_p<N, C, T> ();
+  test_unsigned_known_in_range_p<N, C, T> ();
+}
+
+/* Test things that are specific to coefficients of type wide_int,
+   using a poly_int with N coefficients.  */
+
+template<unsigned int N>
+static void
+test_wide_int ()
+{
+  test_wide_int_from<N> ();
+
+  test_to_shwi<N> (wi::mask (63, true, 77), -1, HOST_WIDE_INT_MIN);
+  test_to_shwi<N> (wi::mask (63, false, 77), 1, HOST_WIDE_INT_MAX);
+  test_to_uhwi<N> (wide_int (wi::zero (94)), -1, 0U);
+  test_to_uhwi<N> (wi::mask (64, false, 94), 1, HOST_WIDE_INT_M1U);
+
+  test_force_hwi<N> (wi::mask (66, false, 81));
+
+  test_wide_int_sext<N> ();
+  test_wide_int_zext<N> ();
+  test_wide_int_add<N> ();
+  test_wide_int_sub<N> ();
+  test_wide_int_mul<N> ();
+  test_wide_int_neg<N> ();
+}
+
+/* Run the tests that are common to all coefficient counts N.  */
+
+template<unsigned int N>
+static void
+test_num_coeffs_core ()
+{
+  test_unsigned<N, unsigned short, HOST_WIDE_INT,
+               poly_int<N, unsigned short> > ();
+  test_signed<N, HOST_WIDE_INT, HOST_WIDE_INT,
+             poly_int<N, HOST_WIDE_INT> > ();
+  test_unsigned<N, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
+               poly_int<N, unsigned HOST_WIDE_INT> >();
+
+  test_general<N, wide_int, wide_int, poly_int<N, wide_int> > ();
+
+  test_hwi<N, unsigned short, poly_int<N, unsigned short> > ();
+  test_hwi<N, HOST_WIDE_INT, poly_int<N, HOST_WIDE_INT> > ();
+  test_hwi<N, unsigned HOST_WIDE_INT, poly_int<N, unsigned HOST_WIDE_INT> > ();
+
+  test_wide_int<N> ();
+  test_fixed_int<N, offset_int> ();
+  test_fixed_int<N, widest_int> ();
+
+  test_type_promotions<N> ();
+  test_shwi<N> ();
+  test_uhwi<N> ();
+}
+
+/* Run extra tests for the most important coefficient counts N.  */
+
+template<unsigned int N>
+static void
+test_num_coeffs_extra ()
+{
+  /* Test the most common POD types.  */
+  test_unsigned<N, unsigned short, HOST_WIDE_INT,
+               poly_int_pod<N, unsigned short> > ();
+  test_signed<N, HOST_WIDE_INT, HOST_WIDE_INT,
+             poly_int_pod<N, HOST_WIDE_INT> > ();
+  test_unsigned<N, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
+               poly_int_pod<N, unsigned HOST_WIDE_INT> > ();
+
+  /* Test some coefficient types that weren't covered in the core tests.  */
+  test_signed<N, int, HOST_WIDE_INT,
+             poly_int<N, int> > ();
+  test_signed<N, offset_int, offset_int,
+             poly_int<N, offset_int> > ();
+  test_signed<N, widest_int, widest_int,
+             poly_int<N, widest_int> > ();
+}
index e17b016af040f2d08a93c50d473ede2268e9d4ba..bbfde909aeb17654568dd7ec2d8152b52ad7eb09 100644 (file)
@@ -293,7 +293,7 @@ along with GCC; see the file COPYING3.  If not see
 
 /* The type of result produced by a unary operation on type T.  */
 #define WI_UNARY_RESULT(T) \
-  typename wi::unary_traits <T>::result_type
+  typename wi::binary_traits <T, T>::result_type
 
 /* Define a variable RESULT to hold the result of a binary operation on
    X and Y, which have types T1 and T2 respectively.  Define VAL to
@@ -390,11 +390,6 @@ namespace wi
            enum precision_type P2 = int_traits <T2>::precision_type>
   struct binary_traits;
 
-  /* The result of a unary operation on T is the same as the result of
-     a binary operation on two values of type T.  */
-  template <typename T>
-  struct unary_traits : public binary_traits <T, T> {};
-
   /* Specify the result type for each supported combination of binary
      inputs.  Note that CONST_PRECISION and VAR_PRECISION cannot be
      mixed, in order to give stronger type checking.  When both inputs
@@ -423,6 +418,7 @@ namespace wi
                               <int_traits <T2>::precision> > result_type;
     typedef result_type operator_result;
     typedef bool predicate_result;
+    typedef result_type signed_shift_result_type;
     typedef bool signed_predicate_result;
   };
 
@@ -727,7 +723,7 @@ public:
   ASSIGNMENT_OPERATOR (operator +=, add)
   ASSIGNMENT_OPERATOR (operator -=, sub)
   ASSIGNMENT_OPERATOR (operator *=, mul)
-  SHIFT_ASSIGNMENT_OPERATOR (operator <<=, <<)
+  ASSIGNMENT_OPERATOR (operator <<=, lshift)
   SHIFT_ASSIGNMENT_OPERATOR (operator >>=, >>)
   INCDEC_OPERATOR (operator ++, 1)
   INCDEC_OPERATOR (operator --, -1)
@@ -1513,6 +1509,7 @@ namespace wi
      and precision PRECISION.  */
   struct hwi_with_prec
   {
+    hwi_with_prec () {}
     hwi_with_prec (HOST_WIDE_INT, unsigned int, signop);
     HOST_WIDE_INT val;
     unsigned int precision;
@@ -1580,6 +1577,30 @@ wi::two (unsigned int precision)
   return wi::shwi (2, precision);
 }
 
+namespace wi
+{
+  /* ints_for<T>::zero (X) returns a zero that, when asssigned to a T,
+     gives that T the same precision as X.  */
+  template<typename T, precision_type = int_traits<T>::precision_type>
+  struct ints_for
+  {
+    static int zero (const T &) { return 0; }
+  };
+
+  template<typename T>
+  struct ints_for<T, VAR_PRECISION>
+  {
+    static hwi_with_prec zero (const T &);
+  };
+}
+
+template<typename T>
+inline wi::hwi_with_prec
+wi::ints_for<T, wi::VAR_PRECISION>::zero (const T &x)
+{
+  return wi::zero (wi::get_precision (x));
+}
+
 namespace wi
 {
   template <>
@@ -3152,6 +3173,14 @@ SIGNED_BINARY_PREDICATE (operator >=, ges_p)
     return wi::F (x, y); \
   }
 
+#define SHIFT_OPERATOR(OP, F) \
+  template<typename T1, typename T2> \
+  WI_BINARY_OPERATOR_RESULT (T1, T1) \
+  OP (const T1 &x, const T2 &y) \
+  { \
+    return wi::F (x, y); \
+  }
+
 UNARY_OPERATOR (operator ~, bit_not)
 UNARY_OPERATOR (operator -, neg)
 BINARY_PREDICATE (operator ==, eq_p)
@@ -3162,23 +3191,32 @@ BINARY_OPERATOR (operator ^, bit_xor)
 BINARY_OPERATOR (operator +, add)
 BINARY_OPERATOR (operator -, sub)
 BINARY_OPERATOR (operator *, mul)
+SHIFT_OPERATOR (operator <<, lshift)
 
 #undef UNARY_OPERATOR
 #undef BINARY_PREDICATE
 #undef BINARY_OPERATOR
+#undef SHIFT_OPERATOR
+
+template <typename T1, typename T2>
+inline WI_SIGNED_SHIFT_RESULT (T1, T2)
+operator >> (const T1 &x, const T2 &y)
+{
+  return wi::arshift (x, y);
+}
 
 template <typename T1, typename T2>
 inline WI_SIGNED_SHIFT_RESULT (T1, T2)
-operator << (const T1 &x, const T2 &y)
+operator / (const T1 &x, const T2 &y)
 {
-  return wi::lshift (x, y);
+  return wi::sdiv_trunc (x, y);
 }
 
 template <typename T1, typename T2>
 inline WI_SIGNED_SHIFT_RESULT (T1, T2)
-operator >> (const T1 &x, const T2 &y)
+operator % (const T1 &x, const T2 &y)
 {
-  return wi::arshift (x, y);
+  return wi::smod_trunc (x, y);
 }
 
 template<typename T>