From: Richard Sandiford Date: Thu, 14 Dec 2017 00:06:02 +0000 (+0000) Subject: poly_int: add poly-int.h X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e535b963b4a39e041cc81e2879cfb637d60c720d;p=gcc.git poly_int: add poly-int.h 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 Alan Hayward David Sherwood 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 Co-Authored-By: David Sherwood From-SVN: r255617 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 272bb7696f2..9d4869eadba 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,37 @@ +2017-12-14 Richard Sandiford + Alan Hayward + David Sherwood + + * 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 Dominik Vogt diff --git a/gcc/Makefile.in b/gcc/Makefile.in index f6e59cde8df..115cbe53d0b 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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 diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 410583e1ce2..9d94e492299 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -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" diff --git a/gcc/doc/gccint.texi b/gcc/doc/gccint.texi index 817ed800cd2..849c67c787e 100644 --- a/gcc/doc/gccint.texi +++ b/gcc/doc/gccint.texi @@ -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 index 00000000000..1023e823cb3 --- /dev/null +++ b/gcc/doc/poly-int.texi @@ -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 + diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index dd3c0d3cfc1..c28bdd5149b 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -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 diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index b39c7efa415..45675e38d71 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -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 diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 57b83a8e542..ff0067360cd 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -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 diff --git a/gcc/genmodes.c b/gcc/genmodes.c index 4eb8ee56d88..e7ee3ab1ad0 100644 --- a/gcc/genmodes.c +++ b/gcc/genmodes.c @@ -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 index 00000000000..1c62ff88ff7 --- /dev/null +++ b/gcc/poly-int-types.h @@ -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 +. */ + +#ifndef HAVE_POLY_INT_TYPES_H +#define HAVE_POLY_INT_TYPES_H + +typedef poly_int_pod poly_uint16_pod; +typedef poly_int_pod poly_int64_pod; +typedef poly_int_pod poly_uint64_pod; +typedef poly_int_pod poly_offset_int_pod; +typedef poly_int_pod poly_wide_int_pod; +typedef poly_int_pod poly_widest_int_pod; + +typedef poly_int poly_uint16; +typedef poly_int poly_int64; +typedef poly_int poly_uint64; +typedef poly_int poly_offset_int; +typedef poly_int poly_wide_int; +typedef poly_int poly_wide_int_ref; +typedef poly_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 index 00000000000..8472e519ecb --- /dev/null +++ b/gcc/poly-int.h @@ -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 +. */ + +/* 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 class poly_int_pod; +template class poly_int; + +/* poly_coeff_traiits describes the properties of a poly_int + coefficient type T: + + - poly_coeff_traits::rank is less than poly_coeff_traits::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::int_type is the type to which an integer + literal should be cast before comparing it with T. + + - poly_coeff_traits::precision is the number of bits that T can hold. + + - poly_coeff_traits::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::max_value, if defined, is the maximum value of T. + + - poly_coeff_traits::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::precision_type> +struct poly_coeff_traits; + +template +struct poly_coeff_traits +{ + 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 +struct poly_coeff_traits +{ + 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 +struct poly_coeff_traits +{ + 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::precision; + static const int rank = precision * 2 / CHAR_BIT; +}; + +/* Information about a pair of coefficient types. */ +template +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::signedness + == poly_coeff_traits::signedness + ? (poly_coeff_traits::precision + >= poly_coeff_traits::precision) + : (poly_coeff_traits::signedness == 1 + && poly_coeff_traits::signedness == 0 + && (poly_coeff_traits::precision + > poly_coeff_traits::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::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::lossless_p> +struct if_lossless; +template +struct if_lossless +{ + typedef T3 type; +}; + +/* poly_int_traits describes an integer type T that might be polynomial + or non-polynomial: + + - poly_int_traits::is_poly is true if T is a poly_int-based type + and false otherwise. + + - poly_int_traits::num_coeffs gives the number of coefficients in T + if T is a poly_int and 1 otherwise. + + - poly_int_traits::coeff_type gives the coefficent type of T if T + is a poly_int and T itself otherwise + + - poly_int_traits::int_type is a shorthand for + typename poly_coeff_traits::int_type. */ +template +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::int_type int_type; +}; +template +struct poly_int_traits > +{ + static const bool is_poly = true; + static const unsigned int num_coeffs = N; + typedef C coeff_type; + typedef typename poly_coeff_traits::int_type int_type; +}; +template +struct poly_int_traits > : poly_int_traits > +{ +}; + +/* SFINAE class that makes T2 available as "type" if T1 is a non-polynomial + type. */ +template::is_poly> +struct if_nonpoly {}; +template +struct if_nonpoly +{ + typedef T2 type; +}; + +/* SFINAE class that makes T3 available as "type" if both T1 and T2 are + non-polynomial types. */ +template::is_poly, + bool is_poly2 = poly_int_traits::is_poly> +struct if_nonpoly2 {}; +template +struct if_nonpoly2 +{ + typedef T3 type; +}; + +/* SFINAE class that makes T2 available as "type" if T1 is a polynomial + type. */ +template::is_poly> +struct if_poly {}; +template +struct if_poly +{ + typedef T2 type; +}; + +/* poly_result describes the result of an operation on two + types T1 and T2, where at least one of the types is polynomial: + + - poly_result::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::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::type would also work, but casting to this + type is more efficient. */ +template::result_kind> +struct poly_result; + +/* Promote pair to HOST_WIDE_INT. */ +template +struct poly_result +{ + 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 +struct poly_result +{ + 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 +struct poly_result +{ + 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::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::type) + +/* Likewise in reverse. */ +#define CONST_POLY_COEFF(T1, C2) \ + POLY_POLY_COEFF (typename if_nonpoly::type, C2) + +/* The result type for a binary operation on poly_int and + poly_int. */ +#define POLY_POLY_RESULT(N, C1, C2) poly_int + +/* Enforce that T2 is non-polynomial and provide the result type + for a binary operation on poly_int and T2. */ +#define POLY_CONST_RESULT(N, C1, T2) poly_int + +/* Enforce that T1 is non-polynomial and provide the result type + for a binary operation on T1 and poly_int. */ +#define CONST_POLY_RESULT(N, T1, C2) poly_int + +/* 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::type, \ + typename if_nonpoly::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::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::coeff_type, \ + typename poly_int_traits::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::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::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 +class poly_int_pod +{ +public: + template + poly_int_pod &operator = (const poly_int_pod &); + template + typename if_nonpoly::type &operator = (const Ca &); + + template + poly_int_pod &operator += (const poly_int_pod &); + template + typename if_nonpoly::type &operator += (const Ca &); + + template + poly_int_pod &operator -= (const poly_int_pod &); + template + typename if_nonpoly::type &operator -= (const Ca &); + + template + typename if_nonpoly::type &operator *= (const Ca &); + + poly_int_pod &operator <<= (unsigned int); + + bool is_constant () const; + + template + typename if_lossless::type is_constant (T *) const; + + C to_constant () const; + + template + static poly_int from (const poly_int_pod &, unsigned int, + signop); + template + static poly_int from (const poly_int_pod &, signop); + + bool to_shwi (poly_int_pod *) const; + bool to_uhwi (poly_int_pod *) const; + poly_int force_shwi () const; + poly_int force_uhwi () const; + +#if POLY_INT_CONVERSION + operator C () const; +#endif + + C coeffs[N]; +}; + +template +template +inline poly_int_pod& +poly_int_pod::operator = (const poly_int_pod &a) +{ + for (unsigned int i = 0; i < N; i++) + POLY_SET_COEFF (C, *this, i, a.coeffs[i]); + return *this; +} + +template +template +inline typename if_nonpoly >::type & +poly_int_pod::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::zero (this->coeffs[0])); + return *this; +} + +template +template +inline poly_int_pod& +poly_int_pod::operator += (const poly_int_pod &a) +{ + for (unsigned int i = 0; i < N; i++) + this->coeffs[i] += a.coeffs[i]; + return *this; +} + +template +template +inline typename if_nonpoly >::type & +poly_int_pod::operator += (const Ca &a) +{ + this->coeffs[0] += a; + return *this; +} + +template +template +inline poly_int_pod& +poly_int_pod::operator -= (const poly_int_pod &a) +{ + for (unsigned int i = 0; i < N; i++) + this->coeffs[i] -= a.coeffs[i]; + return *this; +} + +template +template +inline typename if_nonpoly >::type & +poly_int_pod::operator -= (const Ca &a) +{ + this->coeffs[0] -= a; + return *this; +} + +template +template +inline typename if_nonpoly >::type & +poly_int_pod::operator *= (const Ca &a) +{ + for (unsigned int i = 0; i < N; i++) + this->coeffs[i] *= a; + return *this; +} + +template +inline poly_int_pod& +poly_int_pod::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 +inline bool +poly_int_pod::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 +template +inline typename if_lossless::type +poly_int_pod::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 +inline C +poly_int_pod::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 +template +inline poly_int +poly_int_pod::from (const poly_int_pod &a, + unsigned int bitsize, signop sgn) +{ + poly_int 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 +template +inline poly_int +poly_int_pod::from (const poly_int_pod &a, signop sgn) +{ + poly_int 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 +inline bool +poly_int_pod::to_shwi (poly_int_pod *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 +inline bool +poly_int_pod::to_uhwi (poly_int_pod *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 +inline poly_int +poly_int_pod::force_shwi () const +{ + poly_int_pod 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 +inline poly_int +poly_int_pod::force_uhwi () const +{ + poly_int_pod 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 +inline +poly_int_pod::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 +class poly_int : public poly_int_pod +{ +public: + poly_int () {} + + template + poly_int (const poly_int &); + template + poly_int (const poly_int_pod &); + template + poly_int (const C0 &); + template + poly_int (const C0 &, const C1 &); + + template + poly_int &operator = (const poly_int_pod &); + template + typename if_nonpoly::type &operator = (const Ca &); + + template + poly_int &operator += (const poly_int_pod &); + template + typename if_nonpoly::type &operator += (const Ca &); + + template + poly_int &operator -= (const poly_int_pod &); + template + typename if_nonpoly::type &operator -= (const Ca &); + + template + typename if_nonpoly::type &operator *= (const Ca &); + + poly_int &operator <<= (unsigned int); +}; + +template +template +inline +poly_int::poly_int (const poly_int &a) +{ + for (unsigned int i = 0; i < N; i++) + POLY_SET_COEFF (C, *this, i, a.coeffs[i]); +} + +template +template +inline +poly_int::poly_int (const poly_int_pod &a) +{ + for (unsigned int i = 0; i < N; i++) + POLY_SET_COEFF (C, *this, i, a.coeffs[i]); +} + +template +template +inline +poly_int::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::zero (this->coeffs[0])); +} + +template +template +inline +poly_int::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::zero (this->coeffs[0])); +} + +template +template +inline poly_int& +poly_int::operator = (const poly_int_pod &a) +{ + for (unsigned int i = 0; i < N; i++) + this->coeffs[i] = a.coeffs[i]; + return *this; +} + +template +template +inline typename if_nonpoly >::type & +poly_int::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::zero (this->coeffs[0]); + return *this; +} + +template +template +inline poly_int& +poly_int::operator += (const poly_int_pod &a) +{ + for (unsigned int i = 0; i < N; i++) + this->coeffs[i] += a.coeffs[i]; + return *this; +} + +template +template +inline typename if_nonpoly >::type & +poly_int::operator += (const Ca &a) +{ + this->coeffs[0] += a; + return *this; +} + +template +template +inline poly_int& +poly_int::operator -= (const poly_int_pod &a) +{ + for (unsigned int i = 0; i < N; i++) + this->coeffs[i] -= a.coeffs[i]; + return *this; +} + +template +template +inline typename if_nonpoly >::type & +poly_int::operator -= (const Ca &a) +{ + this->coeffs[0] -= a; + return *this; +} + +template +template +inline typename if_nonpoly >::type & +poly_int::operator *= (const Ca &a) +{ + for (unsigned int i = 0; i < N; i++) + this->coeffs[i] *= a; + return *this; +} + +template +inline poly_int& +poly_int::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 +inline typename if_nonpoly::type +coeffs_in_range_p (const Ca &a, const Cb &b, const Cc &c) +{ + return a >= b && a <= c; +} + +template +inline typename if_nonpoly::type +coeffs_in_range_p (const poly_int_pod &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 +inline poly_int +shwi (const poly_int_pod &a, unsigned int precision) +{ + poly_int 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 +inline poly_int +uhwi (const poly_int_pod &a, unsigned int precision) +{ + poly_int 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 +inline POLY_POLY_RESULT (N, Ca, Ca) +sext (const poly_int_pod &a, unsigned int precision) +{ + typedef POLY_POLY_COEFF (Ca, Ca) C; + poly_int 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 +inline POLY_POLY_RESULT (N, Ca, Ca) +zext (const poly_int_pod &a, unsigned int precision) +{ + typedef POLY_POLY_COEFF (Ca, Ca) C; + poly_int r; + for (unsigned int i = 0; i < N; i++) + POLY_SET_COEFF (C, r, i, wi::zext (a.coeffs[i], precision)); + return r; +} +} + +template +inline POLY_POLY_RESULT (N, Ca, Cb) +operator + (const poly_int_pod &a, const poly_int_pod &b) +{ + typedef POLY_CAST (Ca, Cb) NCa; + typedef POLY_POLY_COEFF (Ca, Cb) C; + poly_int 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 +inline POLY_CONST_RESULT (N, Ca, Cb) +operator + (const poly_int_pod &a, const Cb &b) +{ + typedef POLY_CAST (Ca, Cb) NCa; + typedef POLY_CONST_COEFF (Ca, Cb) C; + poly_int 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 +inline CONST_POLY_RESULT (N, Ca, Cb) +operator + (const Ca &a, const poly_int_pod &b) +{ + typedef POLY_CAST (Cb, Ca) NCb; + typedef CONST_POLY_COEFF (Ca, Cb) C; + poly_int 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 +inline poly_int +add (const poly_int_pod &a, const poly_int_pod &b) +{ + typedef WI_BINARY_RESULT (Ca, Cb) C; + poly_int 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 +inline poly_int +add (const poly_int_pod &a, const Cb &b) +{ + typedef WI_BINARY_RESULT (Ca, Cb) C; + poly_int 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::zero (b))); + return r; +} + +template +inline poly_int +add (const Ca &a, const poly_int_pod &b) +{ + typedef WI_BINARY_RESULT (Ca, Cb) C; + poly_int 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::zero (a), + b.coeffs[i])); + return r; +} + +template +inline poly_int +add (const poly_int_pod &a, const poly_int_pod &b, + signop sgn, bool *overflow) +{ + typedef WI_BINARY_RESULT (Ca, Cb) C; + poly_int 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 +inline POLY_POLY_RESULT (N, Ca, Cb) +operator - (const poly_int_pod &a, const poly_int_pod &b) +{ + typedef POLY_CAST (Ca, Cb) NCa; + typedef POLY_POLY_COEFF (Ca, Cb) C; + poly_int 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 +inline POLY_CONST_RESULT (N, Ca, Cb) +operator - (const poly_int_pod &a, const Cb &b) +{ + typedef POLY_CAST (Ca, Cb) NCa; + typedef POLY_CONST_COEFF (Ca, Cb) C; + poly_int 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 +inline CONST_POLY_RESULT (N, Ca, Cb) +operator - (const Ca &a, const poly_int_pod &b) +{ + typedef POLY_CAST (Cb, Ca) NCb; + typedef CONST_POLY_COEFF (Ca, Cb) C; + poly_int 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 +inline poly_int +sub (const poly_int_pod &a, const poly_int_pod &b) +{ + typedef WI_BINARY_RESULT (Ca, Cb) C; + poly_int 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 +inline poly_int +sub (const poly_int_pod &a, const Cb &b) +{ + typedef WI_BINARY_RESULT (Ca, Cb) C; + poly_int 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::zero (b))); + return r; +} + +template +inline poly_int +sub (const Ca &a, const poly_int_pod &b) +{ + typedef WI_BINARY_RESULT (Ca, Cb) C; + poly_int 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::zero (a), + b.coeffs[i])); + return r; +} + +template +inline poly_int +sub (const poly_int_pod &a, const poly_int_pod &b, + signop sgn, bool *overflow) +{ + typedef WI_BINARY_RESULT (Ca, Cb) C; + poly_int 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 +inline POLY_POLY_RESULT (N, Ca, Ca) +operator - (const poly_int_pod &a) +{ + typedef POLY_CAST (Ca, Ca) NCa; + typedef POLY_POLY_COEFF (Ca, Ca) C; + poly_int 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 +inline poly_int +neg (const poly_int_pod &a) +{ + typedef WI_UNARY_RESULT (Ca) C; + poly_int r; + for (unsigned int i = 0; i < N; i++) + POLY_SET_COEFF (C, r, i, wi::neg (a.coeffs[i])); + return r; +} + +template +inline poly_int +neg (const poly_int_pod &a, bool *overflow) +{ + typedef WI_UNARY_RESULT (Ca) C; + poly_int 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 +inline POLY_POLY_RESULT (N, Ca, Ca) +operator ~ (const poly_int_pod &a) +{ + if (N >= 2) + return -1 - a; + return ~a.coeffs[0]; +} + +template +inline POLY_CONST_RESULT (N, Ca, Cb) +operator * (const poly_int_pod &a, const Cb &b) +{ + typedef POLY_CAST (Ca, Cb) NCa; + typedef POLY_CONST_COEFF (Ca, Cb) C; + poly_int r; + for (unsigned int i = 0; i < N; i++) + POLY_SET_COEFF (C, r, i, NCa (a.coeffs[i]) * b); + return r; +} + +template +inline CONST_POLY_RESULT (N, Ca, Cb) +operator * (const Ca &a, const poly_int_pod &b) +{ + typedef POLY_CAST (Ca, Cb) NCa; + typedef CONST_POLY_COEFF (Ca, Cb) C; + poly_int 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 +inline poly_int +mul (const poly_int_pod &a, const Cb &b) +{ + typedef WI_BINARY_RESULT (Ca, Cb) C; + poly_int r; + for (unsigned int i = 0; i < N; i++) + POLY_SET_COEFF (C, r, i, wi::mul (a.coeffs[i], b)); + return r; +} + +template +inline poly_int +mul (const Ca &a, const poly_int_pod &b) +{ + typedef WI_BINARY_RESULT (Ca, Cb) C; + poly_int r; + for (unsigned int i = 0; i < N; i++) + POLY_SET_COEFF (C, r, i, wi::mul (a, b.coeffs[i])); + return r; +} + +template +inline poly_int +mul (const poly_int_pod &a, const Cb &b, + signop sgn, bool *overflow) +{ + typedef WI_BINARY_RESULT (Ca, Cb) C; + poly_int 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 +inline POLY_POLY_RESULT (N, Ca, Ca) +operator << (const poly_int_pod &a, const Cb &b) +{ + typedef POLY_CAST (Ca, Ca) NCa; + typedef POLY_POLY_COEFF (Ca, Ca) C; + poly_int 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 +inline poly_int +lshift (const poly_int_pod &a, const Cb &b) +{ + typedef WI_BINARY_RESULT (Ca, Ca) C; + poly_int 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 +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 +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 +inline bool +maybe_eq (const poly_int_pod &a, const poly_int_pod &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 +inline typename if_nonpoly::type +maybe_eq (const poly_int_pod &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 +inline typename if_nonpoly::type +maybe_eq (const Ca &a, const poly_int_pod &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 +inline typename if_nonpoly2::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 +inline bool +maybe_ne (const poly_int_pod &a, const poly_int_pod &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 +inline typename if_nonpoly::type +maybe_ne (const poly_int_pod &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 +inline typename if_nonpoly::type +maybe_ne (const Ca &a, const poly_int_pod &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 +inline typename if_nonpoly2::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 +inline bool +maybe_le (const poly_int_pod &a, const poly_int_pod &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 +inline typename if_nonpoly::type +maybe_le (const poly_int_pod &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 +inline typename if_nonpoly::type +maybe_le (const Ca &a, const poly_int_pod &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 +inline typename if_nonpoly2::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 +inline bool +maybe_lt (const poly_int_pod &a, const poly_int_pod &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 +inline typename if_nonpoly::type +maybe_lt (const poly_int_pod &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 +inline typename if_nonpoly::type +maybe_lt (const Ca &a, const poly_int_pod &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 +inline typename if_nonpoly2::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 +inline bool +ordered_p (const T1 &a, const T2 &b) +{ + return ((poly_int_traits::num_coeffs == 1 + && poly_int_traits::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 +inline POLY_POLY_RESULT (N, Ca, Cb) +ordered_min (const poly_int_pod &a, const poly_int_pod &b) +{ + if (known_le (a, b)) + return a; + else + { + if (N > 1) + gcc_checking_assert (known_le (b, a)); + return b; + } +} + +template +inline CONST_POLY_RESULT (N, Ca, Cb) +ordered_min (const Ca &a, const poly_int_pod &b) +{ + if (known_le (a, b)) + return a; + else + { + if (N > 1) + gcc_checking_assert (known_le (b, a)); + return b; + } +} + +template +inline POLY_CONST_RESULT (N, Ca, Cb) +ordered_min (const poly_int_pod &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 +inline POLY_POLY_RESULT (N, Ca, Cb) +ordered_max (const poly_int_pod &a, const poly_int_pod &b) +{ + if (known_le (a, b)) + return b; + else + { + if (N > 1) + gcc_checking_assert (known_le (b, a)); + return a; + } +} + +template +inline CONST_POLY_RESULT (N, Ca, Cb) +ordered_max (const Ca &a, const poly_int_pod &b) +{ + if (known_le (a, b)) + return b; + else + { + if (N > 1) + gcc_checking_assert (known_le (b, a)); + return a; + } +} + +template +inline POLY_CONST_RESULT (N, Ca, Cb) +ordered_max (const poly_int_pod &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 +inline Ca +constant_lower_bound (const poly_int_pod &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 +inline POLY_CONST_RESULT (N, Ca, Cb) +lower_bound (const poly_int_pod &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 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 +inline CONST_POLY_RESULT (N, Ca, Cb) +lower_bound (const Ca &a, const poly_int_pod &b) +{ + return lower_bound (b, a); +} + +template +inline POLY_POLY_RESULT (N, Ca, Cb) +lower_bound (const poly_int_pod &a, const poly_int_pod &b) +{ + typedef POLY_CAST (Ca, Cb) NCa; + typedef POLY_CAST (Cb, Ca) NCb; + typedef POLY_POLY_COEFF (Ca, Cb) C; + + poly_int 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 +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 +inline POLY_CONST_RESULT (N, Ca, Cb) +upper_bound (const poly_int_pod &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 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 +inline CONST_POLY_RESULT (N, Ca, Cb) +upper_bound (const Ca &a, const poly_int_pod &b) +{ + return upper_bound (b, a); +} + +template +inline POLY_POLY_RESULT (N, Ca, Cb) +upper_bound (const poly_int_pod &a, const poly_int_pod &b) +{ + typedef POLY_CAST (Ca, Cb) NCa; + typedef POLY_CAST (Cb, Ca) NCb; + typedef POLY_POLY_COEFF (Ca, Cb) C; + + poly_int 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 +inline POLY_BINARY_COEFF (Ca, Ca) +coeff_gcd (const poly_int_pod &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 +POLY_CONST_RESULT (N, Ca, Cb) +common_multiple (const poly_int_pod &a, Cb b) +{ + POLY_BINARY_COEFF (Ca, Ca) xgcd = coeff_gcd (a); + return a * (least_common_multiple (xgcd, b) / xgcd); +} + +template +inline CONST_POLY_RESULT (N, Ca, Cb) +common_multiple (const Ca &a, const poly_int_pod &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 +POLY_POLY_RESULT (N, Ca, Cb) +force_common_multiple (const poly_int_pod &a, + const poly_int_pod &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 +inline int +compare_sizes_for_sort (const poly_int_pod &a, + const poly_int_pod &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 +inline bool +can_align_p (const poly_int_pod &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 +inline bool +can_align_up (const poly_int_pod &value, Cb align, + poly_int_pod *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 +inline bool +can_align_down (const poly_int_pod &value, Cb align, + poly_int_pod *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 +inline bool +known_equal_after_align_up (const poly_int_pod &a, + const poly_int_pod &b, + Cc align) +{ + poly_int aligned_a; + poly_int 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 +inline bool +known_equal_after_align_down (const poly_int_pod &a, + const poly_int_pod &b, + Cc align) +{ + poly_int aligned_a; + poly_int 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 +inline poly_int +force_align_up (const poly_int_pod &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 +inline poly_int +force_align_down (const poly_int_pod &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 +inline poly_int +aligned_lower_bound (const poly_int_pod &value, Cb align) +{ + poly_int 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 +inline poly_int +aligned_upper_bound (const poly_int_pod &value, Cb align) +{ + poly_int 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 +inline poly_int +force_align_down_and_div (const poly_int_pod &value, Cb align) +{ + gcc_checking_assert (can_align_p (value, align)); + + poly_int 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 +inline poly_int +force_align_up_and_div (const poly_int_pod &value, Cb align) +{ + gcc_checking_assert (can_align_p (value, align)); + + poly_int 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 +inline bool +known_misalignment (const poly_int_pod &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 +inline POLY_BINARY_COEFF (Ca, Ca) +force_get_misalignment (const poly_int_pod &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 +inline POLY_BINARY_COEFF (Ca, Ca) +known_alignment (const poly_int_pod &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 +inline typename if_nonpoly::type +can_ior_p (const poly_int_pod &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 +inline typename if_nonpoly::type +constant_multiple_p (const poly_int_pod &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 +inline typename if_nonpoly::type +constant_multiple_p (Ca a, const poly_int_pod &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 +inline bool +constant_multiple_p (const poly_int_pod &a, + const poly_int_pod &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 +inline typename if_nonpoly2::type +multiple_p (Ca a, Cb b) +{ + return a % b != 0; +} + +/* Return true if A is a (polynomial) multiple of B. */ + +template +inline typename if_nonpoly::type +multiple_p (const poly_int_pod &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 +inline typename if_nonpoly::type +multiple_p (Ca a, const poly_int_pod &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 +inline bool +multiple_p (const poly_int_pod &a, const poly_int_pod &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 +inline typename if_nonpoly2::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 +inline typename if_nonpoly::type +multiple_p (const poly_int_pod &a, Cb b, poly_int_pod *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 +inline typename if_nonpoly::type +multiple_p (Ca a, const poly_int_pod &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 +inline bool +multiple_p (const poly_int_pod &a, const poly_int_pod &b, + poly_int_pod *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 +inline POLY_CONST_RESULT (N, Ca, Cb) +exact_div (const poly_int_pod &a, Cb b) +{ + typedef POLY_CONST_COEFF (Ca, Cb) C; + poly_int 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 +inline POLY_POLY_RESULT (N, Ca, Cb) +exact_div (const poly_int_pod &a, const poly_int_pod &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 +inline typename if_nonpoly2::type +can_div_trunc_p (const poly_int_pod &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 +inline typename if_nonpoly::type +can_div_trunc_p (const poly_int_pod &a, + const poly_int_pod &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 +inline typename if_nonpoly::type +can_div_trunc_p (const poly_int_pod &a, + const poly_int_pod &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 +inline typename if_nonpoly::type +can_div_trunc_p (const poly_int_pod &a, Cb b, + poly_int_pod *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 +inline typename if_nonpoly::type +can_div_trunc_p (const poly_int_pod &a, Cb b, + poly_int_pod *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 +inline typename if_nonpoly::type +can_div_away_from_zero_p (const poly_int_pod &a, + const poly_int_pod &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 +void +print_dec (const poly_int_pod &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 +void +print_dec (const poly_int_pod &value, FILE *file) +{ + STATIC_ASSERT (poly_coeff_traits::signedness >= 0); + print_dec (value, file, + poly_coeff_traits::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 +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 + 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 +struct poly_span_traits +{ + template + static typename if_nonpoly::type + cast (const T &x) { return x; } + + template + static poly_int + cast (const poly_int_pod &x) { return x; } +}; + +/* Return true if SIZE represents a known size, assuming that all-ones + indicates an unknown size. */ + +template +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 +inline bool +maybe_in_range_p (const T1 &val, const T2 &pos, const T3 &size) +{ + typedef poly_span_traits span; + if (known_lt (val, pos)) + return false; + if (!known_size_p (size)) + return true; + if ((poly_int_traits::num_coeffs > 1 + || poly_int_traits::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 +inline bool +known_in_range_p (const T1 &val, const T2 &pos, const T3 &size) +{ + typedef poly_span_traits 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 +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 +inline bool +ranges_known_overlap_p (const T1 &pos1, const T2 &size1, + const T3 &pos2, const T4 &size2) +{ + typedef poly_span_traits span1; + typedef poly_span_traits 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 +inline bool +known_subrange_p (const T1 &pos1, const T2 &size1, + const T3 &pos2, const T4 &size2) +{ + typedef typename poly_int_traits::coeff_type C2; + typedef POLY_BINARY_COEFF (T2, T4) size_diff_type; + typedef poly_span_traits span; + return (known_gt (size1, POLY_INT_TYPE (T2) (0)) + && (poly_coeff_traits::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 +inline typename if_nonpoly::type +endpoint_representable_p (const T &pos, const T &size) +{ + return (!known_size_p (size) + || pos <= poly_coeff_traits::max_value - size); +} + +template +inline bool +endpoint_representable_p (const poly_int_pod &pos, + const poly_int_pod &size) +{ + if (known_size_p (size)) + for (unsigned int i = 0; i < N; ++i) + if (pos.coeffs[i] > poly_coeff_traits::max_value - size.coeffs[i]) + return false; + return true; +} + +template +void +gt_ggc_mx (poly_int_pod *) +{ +} + +template +void +gt_pch_nx (poly_int_pod *) +{ +} + +template +void +gt_pch_nx (poly_int_pod *, 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 diff --git a/gcc/selftest.h b/gcc/selftest.h index 68b2e8ebfc5..ab8a7c0c71c 100644 --- a/gcc/selftest.h +++ b/gcc/selftest.h @@ -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. */ diff --git a/gcc/target.def b/gcc/target.def index b9b45991000..78577d6bf84 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -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 diff --git a/gcc/target.h b/gcc/target.h index 62601933338..9696b4d61e1 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -211,6 +211,21 @@ typedef auto_vec 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 diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 0edc57b0a15..6b3279e4b38 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -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. */ diff --git a/gcc/targhooks.h b/gcc/targhooks.h index e431934cd60..4c6c65cd312 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -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, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4529bcaa185..b80b2f2bf55 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,18 @@ +2017-12-14 Richard Sandiford + Alan Hayward + David Sherwood + + * 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 * gcc.target/powerpc/cpu-builtin-1.c (htm-no-suspend): Add test. diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp index ff3c9764835..057f4e223df 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -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 index 00000000000..099c9d94c42 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/poly-int-01_plugin.c @@ -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 index 00000000000..bf103acba8b --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/poly-int-02_plugin.c @@ -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 index 00000000000..0c08ead8b75 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/poly-int-03_plugin.c @@ -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 index 00000000000..8b0a5f91fb4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/poly-int-04_plugin.c @@ -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 index 00000000000..62493118fe4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/poly-int-05_plugin.c @@ -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 index 00000000000..ee4308c26bf --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/poly-int-06_plugin.c @@ -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 (); + test_signed_2 (); + test_signed_2 (); + test_signed_2 (); + + test_ordered_2 (); + test_ordered_2 (); + test_ordered_2 (); + + 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 index 00000000000..e3203d9f3e1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/poly-int-07_plugin.c @@ -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 index 00000000000..fe284d59433 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/poly-int-test-1.c @@ -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 index 00000000000..b195f67aaf4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/poly-int-tests.h @@ -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 +struct coeff_helper +{ + static inline const T &make (const T &x) { return x; } +}; + +template<> +struct coeff_helper +{ + template + 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 +struct poly_helper +{ + typedef typename poly_int_traits::coeff_type C; + template + static T make (const T1 &a, const T2 &b, const T3 &c); +}; + +template +template +inline T +poly_helper::make (const T1 &a, const T2 &b, const T3 &c) +{ + T res; + res = coeff_helper::make (a); + if (poly_int_traits::num_coeffs >= 2) + res.coeffs[1] = coeff_helper::make (b); + if (poly_int_traits::num_coeffs >= 3) + res.coeffs[2] = coeff_helper::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::signedness, 0); + ASSERT_EQ (poly_coeff_traits::max_value, 0xffff); + + ASSERT_EQ (poly_coeff_traits::signedness, 1); + ASSERT_EQ (poly_coeff_traits::max_value, INT_MAX); + + ASSERT_EQ (poly_coeff_traits::signedness, 0); + ASSERT_EQ (poly_coeff_traits::max_value, UINT_MAX); + + ASSERT_EQ (poly_coeff_traits::signedness, 1); + ASSERT_EQ (poly_coeff_traits::max_value, HOST_WIDE_INT_MAX); + + ASSERT_EQ (poly_coeff_traits::signedness, 0); + ASSERT_EQ (poly_coeff_traits::max_value, + HOST_WIDE_INT_M1U); + + ASSERT_EQ (poly_coeff_traits::signedness, -1); + ASSERT_EQ (poly_coeff_traits::signedness, 1); + ASSERT_EQ (poly_coeff_traits::signedness, 1); +} + +/* Test poly_int_traits. */ + +template +static void +test_poly_int_traits () +{ + /* Check the properties of poly_int_traits. */ + ASSERT_FALSE (poly_int_traits::is_poly); + ASSERT_EQ (poly_int_traits::num_coeffs, 1); + ASSERT_EQ ((C *) 0 - (typename poly_int_traits::coeff_type *) 0, 0); + + /* Check the properties of poly_int_traits. */ + ASSERT_TRUE (poly_int_traits::is_poly); + ASSERT_EQ (poly_int_traits::num_coeffs, N); + ASSERT_EQ ((C *) 0 - (typename poly_int_traits::coeff_type *) 0, 0); +} + +/* Test the handling of constants. */ + +template +static void +test_constants () +{ + typedef coeff_helper ch; + T zero, one, two; + poly_int 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 +static void +test_plus_equals () +{ + typedef poly_helper 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 +static void +test_minus_equals () +{ + typedef poly_helper 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 +static void +test_times_equals () +{ + typedef poly_helper 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 +static void +test_shl_equals () +{ + typedef poly_helper 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 +static void +test_is_constant () +{ + typedef poly_helper 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 +static void +test_to_constant () +{ + typedef poly_helper 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 +static void +test_addition () +{ + typedef poly_helper 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 +static void +test_subtraction () +{ + typedef poly_helper ph; + typedef poly_helper< poly_int > rph; + typedef poly_helper< poly_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 +static void +test_negation () +{ + typedef poly_helper ph; + typedef poly_helper< poly_int > rph; + typedef poly_helper< poly_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 +static void +test_multiplication () +{ + typedef poly_helper 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 +static void +test_shift_left () +{ + typedef poly_helper 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 +static void +test_maybe_ne () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_known_eq () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_can_align_p () +{ + typedef poly_helper 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 +static void +test_can_align_up () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_can_align_down () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_known_equal_after_align_up () +{ + typedef poly_helper 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 +static void +test_known_equal_after_align_down () +{ + typedef poly_helper 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 +static void +test_force_align_up () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_force_align_down () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_aligned_lower_bound () +{ + typedef poly_helper 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 +static void +test_aligned_upper_bound () +{ + typedef poly_helper 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 +static void +test_known_misalignment () +{ + typedef poly_helper 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 +static void +test_force_get_misalignment () +{ + typedef poly_helper 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 +static void +test_known_alignment () +{ + typedef poly_helper 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 +static void +test_can_ior_p () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +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 +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 +static void +test_maybe_le () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_maybe_lt () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_maybe_ge () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_maybe_gt () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_known_gt () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_known_ge () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_known_lt () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_known_le () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_ordered_p () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_ordered_min () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_ordered_max () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_constant_lower_bound () +{ + typedef poly_helper 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 +static void +test_lower_bound () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_upper_bound () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_compare_sizes_for_sort () +{ + typedef poly_helper 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 +static void +test_force_align_up_and_div () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_force_align_down_and_div () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_constant_multiple_p () +{ + typedef poly_helper 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 +static void +test_multiple_p () +{ + typedef poly_helper 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 +static void +test_multiple_p_with_result () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_exact_div () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_can_div_trunc_p_const () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_can_div_trunc_p_poly () +{ + typedef coeff_helper ch; + typedef poly_helper ph; + + /* Test can_div_trunc_p (T, C) -> T. */ + T quot; + ASSERT_TRUE (can_div_trunc_p (ph::make (22, 0, 0), 5, ")); + ASSERT_KNOWN_EQ (quot, ch::make (4)); + ASSERT_TRUE (can_div_trunc_p (ph::make (45, 40, 24), 4, ")); + ASSERT_KNOWN_EQ (quot, ph::make (11, 10, 6)); + ASSERT_EQ (can_div_trunc_p (ph::make (13, 18, 19), 6, "), 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, "), 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, + ", &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, + ", &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, + ", &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, + ", &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 +static void +test_can_div_away_from_zero_p () +{ + typedef poly_helper 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 +static void +test_known_size_p () +{ + typedef poly_helper 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 +static void +test_maybe_in_range_p () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_known_in_range_p () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_ranges_maybe_overlap_p () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_ranges_known_overlap_p () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_known_subrange_p () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_coeffs_in_range_p (void) +{ + typedef coeff_helper ch; + typedef poly_helper 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 +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 +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 +static void +test_signed_negation () +{ + typedef poly_helper ph; + typedef poly_helper< poly_int > rph; + typedef poly_helper< poly_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 +static void +test_signed_maybe_le () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_maybe_lt () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_maybe_ge () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_maybe_gt () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_known_gt () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_known_ge () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_known_lt () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_known_le () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_ordered_p () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_ordered_min () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_ordered_max () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_lower_bound () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_upper_bound () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_constant_multiple_p () +{ + typedef poly_helper 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 +static void +test_signed_multiple_p () +{ + typedef poly_helper 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 +static void +test_signed_multiple_p_with_result () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_exact_div () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_can_div_trunc_p_const () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_signed_can_div_trunc_p_poly () +{ + typedef coeff_helper ch; + typedef poly_helper ph; + + /* Test can_div_trunc_p (T, C) -> T. */ + T quot; + ASSERT_TRUE (can_div_trunc_p (ph::make (-99, 0, 0), 10, ")); + ASSERT_KNOWN_EQ (quot, ch::make (-9)); + ASSERT_TRUE (can_div_trunc_p (ph::make (7, -63, 81), 9, ")); + ASSERT_KNOWN_EQ (quot, ph::make (0, -7, 9)); + ASSERT_TRUE (can_div_trunc_p (ph::make (15, 44, -55), -11, ")); + ASSERT_KNOWN_EQ (quot, ph::make (-1, -4, 5)); + ASSERT_EQ (can_div_trunc_p (ph::make (-63, -24, -17), -8, "), 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, "), 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, + ", &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, + ", &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, + ", &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, + ", &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, + ", &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 +static void +test_signed_can_div_away_from_zero_p () +{ + typedef poly_helper 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 +static void +test_signed_maybe_in_range_p () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_maybe_le () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_maybe_lt () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_maybe_ge () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_maybe_gt () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_known_gt () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_known_ge () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_known_lt () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_known_le () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_ordered_p () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_ordered_min () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_ordered_max () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_lower_bound () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_upper_bound () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_maybe_in_range_p () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_unsigned_known_in_range_p () +{ + typedef coeff_helper ch; + typedef poly_helper 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 +static void +test_hwi () +{ + typedef coeff_helper ch; + typedef poly_helper 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::to_shwi, using in-range source coefficient value + SRCV (equal to DESTV) and adding DELTA to get an out-of-range value. */ + +template +static void +test_to_shwi (const C &srcv, int delta, HOST_WIDE_INT destv) +{ + typedef poly_helper< poly_int > ps64h; + typedef poly_int T; + typedef poly_helper ph; + poly_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::to_uhwi, using in-range source coefficient value + SRCV (equal to DESTV) and adding DELTA to get an out-of-range value. */ + +template +static void +test_to_uhwi (const C &srcv, int delta, unsigned HOST_WIDE_INT destv) +{ + typedef poly_helper< poly_int > pu64h; + typedef poly_int T; + typedef poly_helper ph; + poly_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::force_shwi and poly_int::force_uhwi, given + that MASK66 has the low 66 bits set and the rest clear. */ + +template +static void +test_force_hwi (const C &mask66) +{ + typedef poly_helper< poly_int > ps64h; + typedef poly_helper< poly_int > pu64h; + typedef poly_int T; + typedef poly_helper ph; + poly_int shwi; + poly_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::from. */ + +template +static void +test_wide_int_from () +{ + typedef poly_helper< poly_int > pu8h; + typedef poly_int T; + typedef poly_helper 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. */ + +template +static void +test_wide_int_sext () +{ + typedef poly_int T; + typedef poly_helper 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. */ + +template +static void +test_wide_int_zext () +{ + typedef poly_int T; + typedef poly_helper 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. */ + +template +static void +test_wide_int_add () +{ + typedef poly_int T; + typedef poly_helper 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. */ + +template +static void +test_wide_int_sub () +{ + typedef poly_int T; + typedef poly_helper 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. */ + +template +static void +test_wide_int_mul () +{ + typedef poly_int T; + typedef poly_helper 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. */ + +template +static void +test_wide_int_neg () +{ + typedef poly_int T; + typedef poly_helper 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 for things that only make sense when C is an + offset_int or widest_int. */ + +template +static void +test_fixed_int (void) +{ + typedef poly_helper< poly_int > pih; + typedef poly_int T; + typedef poly_helper 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 (-(one << 63), -1, HOST_WIDE_INT_MIN); + test_to_shwi ((one << 63) - 1, 1, HOST_WIDE_INT_MAX); + test_to_uhwi (C (0), -1, 0U); + test_to_uhwi ((one << 64) - 1, 1, HOST_WIDE_INT_M1U); + + /* Test force_shwi and force_uhwi. */ + test_force_hwi ((one << 66) - 1); +} + +/* Test type promotions. */ + +template +static void +test_type_promotions () +{ + typedef poly_helper< poly_int > pu16h; + typedef poly_helper< poly_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 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 +static void +test_shwi () +{ + typedef poly_int T; + typedef poly_helper ph; + + poly_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 +static void +test_uhwi () +{ + typedef poly_int T; + typedef poly_helper ph; + + poly_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 +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 +static void +test_nonpoly_type () +{ + test_nonpoly_known_size_p (); +} + +/* Test poly-int.h operations on non-polynomial values. */ + +static void +test_nonpoly () +{ + test_nonpoly_type (); + test_nonpoly_type (); + test_nonpoly_type (); + test_nonpoly_type (); + test_nonpoly_type (); + test_nonpoly_type (); + test_nonpoly_type (); + test_nonpoly_type (); +} + +/* 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 +static void +test_general () +{ + test_poly_int_traits (); + test_constants (); + test_plus_equals (); + test_minus_equals (); + test_times_equals (); + test_shl_equals (); + test_is_constant (); + test_to_constant (); + test_addition (); + test_subtraction (); + test_negation (); + test_multiplication (); + test_shift_left (); + test_maybe_ne (); + test_known_eq (); + test_can_align_p (); + test_can_align_up (); + test_can_align_down (); + test_known_equal_after_align_up (); + test_known_equal_after_align_down (); + test_force_align_up (); + test_force_align_down (); + test_aligned_lower_bound (); + test_aligned_upper_bound (); + test_known_misalignment (); + test_force_get_misalignment (); + test_known_alignment (); + test_can_ior_p (); + test_known_size_p (); +} + +/* Test things that work for poly_int<2, C>, given that C is signed. */ + +template +static void +test_ordered_2 () +{ + test_maybe_eq_2 (); + test_known_ne_2 (); +} + +/* 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 +static void +test_ordered () +{ + test_general (); + test_maybe_le (); + test_maybe_lt (); + test_maybe_ge (); + test_maybe_gt (); + test_known_gt (); + test_known_ge (); + test_known_lt (); + test_known_le (); + test_ordered_p (); + test_ordered_min (); + test_ordered_max (); + test_constant_lower_bound (); + test_lower_bound (); + test_upper_bound (); + test_compare_sizes_for_sort (); + test_force_align_up_and_div (); + test_force_align_down_and_div (); + test_constant_multiple_p (); + test_multiple_p (); + test_multiple_p_with_result (); + test_exact_div (); + test_can_div_trunc_p_const (); + test_can_div_trunc_p_poly (); + test_can_div_away_from_zero_p (); + test_maybe_in_range_p (); + test_known_in_range_p (); + test_ranges_maybe_overlap_p (); + test_ranges_known_overlap_p (); + test_known_subrange_p (); + test_coeffs_in_range_p (); +} + +/* Test things that work for poly_int<2, C>, given that C is signed. */ + +template +static void +test_signed_2 () +{ + test_ordered_2 (); + test_signed_maybe_eq_2 (); + test_signed_known_ne_2 (); +} + +/* 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 +static void +test_signed () +{ + test_ordered (); + test_signed_negation (); + test_signed_maybe_le (); + test_signed_maybe_lt (); + test_signed_maybe_ge (); + test_signed_maybe_gt (); + test_signed_known_gt (); + test_signed_known_ge (); + test_signed_known_lt (); + test_signed_known_le (); + test_signed_ordered_p (); + test_signed_ordered_min (); + test_signed_ordered_max (); + test_signed_lower_bound (); + test_signed_upper_bound (); + test_signed_constant_multiple_p (); + test_signed_multiple_p (); + test_signed_multiple_p_with_result (); + test_signed_exact_div (); + test_signed_can_div_trunc_p_const (); + test_signed_can_div_trunc_p_poly (); + test_signed_can_div_away_from_zero_p (); + test_signed_maybe_in_range_p (); +} + +/* 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 +static void +test_unsigned () +{ + test_ordered (); + test_unsigned_maybe_le (); + test_unsigned_maybe_lt (); + test_unsigned_maybe_ge (); + test_unsigned_maybe_gt (); + test_unsigned_known_gt (); + test_unsigned_known_ge (); + test_unsigned_known_lt (); + test_unsigned_known_le (); + test_unsigned_ordered_p (); + test_unsigned_ordered_min (); + test_unsigned_ordered_max (); + test_unsigned_lower_bound (); + test_unsigned_upper_bound (); + test_unsigned_maybe_in_range_p (); + test_unsigned_known_in_range_p (); +} + +/* Test things that are specific to coefficients of type wide_int, + using a poly_int with N coefficients. */ + +template +static void +test_wide_int () +{ + test_wide_int_from (); + + test_to_shwi (wi::mask (63, true, 77), -1, HOST_WIDE_INT_MIN); + test_to_shwi (wi::mask (63, false, 77), 1, HOST_WIDE_INT_MAX); + test_to_uhwi (wide_int (wi::zero (94)), -1, 0U); + test_to_uhwi (wi::mask (64, false, 94), 1, HOST_WIDE_INT_M1U); + + test_force_hwi (wi::mask (66, false, 81)); + + test_wide_int_sext (); + test_wide_int_zext (); + test_wide_int_add (); + test_wide_int_sub (); + test_wide_int_mul (); + test_wide_int_neg (); +} + +/* Run the tests that are common to all coefficient counts N. */ + +template +static void +test_num_coeffs_core () +{ + test_unsigned > (); + test_signed > (); + test_unsigned >(); + + test_general > (); + + test_hwi > (); + test_hwi > (); + test_hwi > (); + + test_wide_int (); + test_fixed_int (); + test_fixed_int (); + + test_type_promotions (); + test_shwi (); + test_uhwi (); +} + +/* Run extra tests for the most important coefficient counts N. */ + +template +static void +test_num_coeffs_extra () +{ + /* Test the most common POD types. */ + test_unsigned > (); + test_signed > (); + test_unsigned > (); + + /* Test some coefficient types that weren't covered in the core tests. */ + test_signed > (); + test_signed > (); + test_signed > (); +} diff --git a/gcc/wide-int.h b/gcc/wide-int.h index e17b016af04..bbfde909aeb 100644 --- a/gcc/wide-int.h +++ b/gcc/wide-int.h @@ -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 ::result_type + typename wi::binary_traits ::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 ::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 - struct unary_traits : public binary_traits {}; - /* 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 ::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::zero (X) returns a zero that, when asssigned to a T, + gives that T the same precision as X. */ + template::precision_type> + struct ints_for + { + static int zero (const T &) { return 0; } + }; + + template + struct ints_for + { + static hwi_with_prec zero (const T &); + }; +} + +template +inline wi::hwi_with_prec +wi::ints_for::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 \ + 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 +inline WI_SIGNED_SHIFT_RESULT (T1, T2) +operator >> (const T1 &x, const T2 &y) +{ + return wi::arshift (x, y); +} template 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 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