aboutsummaryrefslogtreecommitdiff
path: root/gcc/wide-int.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/wide-int.h')
-rw-r--r--gcc/wide-int.h150
1 files changed, 109 insertions, 41 deletions
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
index e93b36ef07a..cb5f9abffe2 100644
--- a/gcc/wide-int.h
+++ b/gcc/wide-int.h
@@ -344,6 +344,23 @@ typedef generic_wide_int <wide_int_ref_storage <false> > wide_int_ref;
namespace wi
{
+ /* Operations that calculate overflow do so even for
+ TYPE_OVERFLOW_WRAPS types. For example, adding 1 to +MAX_INT in
+ an unsigned int is 0 and does not overflow in C/C++, but wi::add
+ will set the overflow argument in case it's needed for further
+ analysis.
+
+ For operations that require overflow, these are the different
+ types of overflow. */
+ enum overflow_type {
+ OVF_NONE = 0,
+ OVF_UNDERFLOW = -1,
+ OVF_OVERFLOW = 1,
+ /* There was an overflow, but we are unsure whether it was an
+ overflow or an underflow. */
+ OVF_UNKNOWN = 2
+ };
+
/* Classifies an integer based on its precision. */
enum precision_type {
/* The integer has both a precision and defined signedness. This allows
@@ -522,7 +539,7 @@ namespace wi
UNARY_FUNCTION bit_not (const T &);
UNARY_FUNCTION neg (const T &);
- UNARY_FUNCTION neg (const T &, bool *);
+ UNARY_FUNCTION neg (const T &, overflow_type *);
UNARY_FUNCTION abs (const T &);
UNARY_FUNCTION ext (const T &, unsigned int, signop);
UNARY_FUNCTION sext (const T &, unsigned int);
@@ -542,33 +559,41 @@ namespace wi
BINARY_FUNCTION bit_or_not (const T1 &, const T2 &);
BINARY_FUNCTION bit_xor (const T1 &, const T2 &);
BINARY_FUNCTION add (const T1 &, const T2 &);
- BINARY_FUNCTION add (const T1 &, const T2 &, signop, bool *);
+ BINARY_FUNCTION add (const T1 &, const T2 &, signop, overflow_type *);
BINARY_FUNCTION sub (const T1 &, const T2 &);
- BINARY_FUNCTION sub (const T1 &, const T2 &, signop, bool *);
+ BINARY_FUNCTION sub (const T1 &, const T2 &, signop, overflow_type *);
BINARY_FUNCTION mul (const T1 &, const T2 &);
- BINARY_FUNCTION mul (const T1 &, const T2 &, signop, bool *);
- BINARY_FUNCTION smul (const T1 &, const T2 &, bool *);
- BINARY_FUNCTION umul (const T1 &, const T2 &, bool *);
+ BINARY_FUNCTION mul (const T1 &, const T2 &, signop, overflow_type *);
+ BINARY_FUNCTION smul (const T1 &, const T2 &, overflow_type *);
+ BINARY_FUNCTION umul (const T1 &, const T2 &, overflow_type *);
BINARY_FUNCTION mul_high (const T1 &, const T2 &, signop);
- BINARY_FUNCTION div_trunc (const T1 &, const T2 &, signop, bool * = 0);
+ BINARY_FUNCTION div_trunc (const T1 &, const T2 &, signop,
+ overflow_type * = 0);
BINARY_FUNCTION sdiv_trunc (const T1 &, const T2 &);
BINARY_FUNCTION udiv_trunc (const T1 &, const T2 &);
- BINARY_FUNCTION div_floor (const T1 &, const T2 &, signop, bool * = 0);
+ BINARY_FUNCTION div_floor (const T1 &, const T2 &, signop,
+ overflow_type * = 0);
BINARY_FUNCTION udiv_floor (const T1 &, const T2 &);
BINARY_FUNCTION sdiv_floor (const T1 &, const T2 &);
- BINARY_FUNCTION div_ceil (const T1 &, const T2 &, signop, bool * = 0);
+ BINARY_FUNCTION div_ceil (const T1 &, const T2 &, signop,
+ overflow_type * = 0);
BINARY_FUNCTION udiv_ceil (const T1 &, const T2 &);
- BINARY_FUNCTION div_round (const T1 &, const T2 &, signop, bool * = 0);
+ BINARY_FUNCTION div_round (const T1 &, const T2 &, signop,
+ overflow_type * = 0);
BINARY_FUNCTION divmod_trunc (const T1 &, const T2 &, signop,
WI_BINARY_RESULT (T1, T2) *);
BINARY_FUNCTION gcd (const T1 &, const T2 &, signop = UNSIGNED);
- BINARY_FUNCTION mod_trunc (const T1 &, const T2 &, signop, bool * = 0);
+ BINARY_FUNCTION mod_trunc (const T1 &, const T2 &, signop,
+ overflow_type * = 0);
BINARY_FUNCTION smod_trunc (const T1 &, const T2 &);
BINARY_FUNCTION umod_trunc (const T1 &, const T2 &);
- BINARY_FUNCTION mod_floor (const T1 &, const T2 &, signop, bool * = 0);
+ BINARY_FUNCTION mod_floor (const T1 &, const T2 &, signop,
+ overflow_type * = 0);
BINARY_FUNCTION umod_floor (const T1 &, const T2 &);
- BINARY_FUNCTION mod_ceil (const T1 &, const T2 &, signop, bool * = 0);
- BINARY_FUNCTION mod_round (const T1 &, const T2 &, signop, bool * = 0);
+ BINARY_FUNCTION mod_ceil (const T1 &, const T2 &, signop,
+ overflow_type * = 0);
+ BINARY_FUNCTION mod_round (const T1 &, const T2 &, signop,
+ overflow_type * = 0);
template <typename T1, typename T2>
bool multiple_of_p (const T1 &, const T2 &, signop);
@@ -606,6 +631,8 @@ namespace wi
template <typename T>
unsigned int min_precision (const T &, signop);
+
+ static inline void accumulate_overflow (overflow_type &, overflow_type);
}
namespace wi
@@ -1700,20 +1727,20 @@ namespace wi
const HOST_WIDE_INT *, unsigned int, unsigned int);
unsigned int add_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int,
const HOST_WIDE_INT *, unsigned int, unsigned int,
- signop, bool *);
+ signop, overflow_type *);
unsigned int sub_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int,
const HOST_WIDE_INT *, unsigned int, unsigned int,
- signop, bool *);
+ signop, overflow_type *);
unsigned int mul_internal (HOST_WIDE_INT *, const HOST_WIDE_INT *,
unsigned int, const HOST_WIDE_INT *,
- unsigned int, unsigned int, signop, bool *,
- bool);
+ unsigned int, unsigned int, signop,
+ overflow_type *, bool);
unsigned int divmod_internal (HOST_WIDE_INT *, unsigned int *,
HOST_WIDE_INT *, const HOST_WIDE_INT *,
unsigned int, unsigned int,
const HOST_WIDE_INT *,
unsigned int, unsigned int,
- signop, bool *);
+ signop, overflow_type *);
}
/* Return the number of bits that integer X can hold. */
@@ -2102,12 +2129,13 @@ wi::neg (const T &x)
return sub (0, x);
}
-/* Return -x. Indicate in *OVERFLOW if X is the minimum signed value. */
+/* Return -x. Indicate in *OVERFLOW if performing the negation would
+ cause an overflow. */
template <typename T>
inline WI_UNARY_RESULT (T)
-wi::neg (const T &x, bool *overflow)
+wi::neg (const T &x, overflow_type *overflow)
{
- *overflow = only_sign_bit_p (x);
+ *overflow = only_sign_bit_p (x) ? OVF_OVERFLOW : OVF_NONE;
return sub (0, x);
}
@@ -2407,7 +2435,7 @@ wi::add (const T1 &x, const T2 &y)
and indicate in *OVERFLOW whether the operation overflowed. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::add (const T1 &x, const T2 &y, signop sgn, bool *overflow)
+wi::add (const T1 &x, const T2 &y, signop sgn, overflow_type *overflow)
{
WI_BINARY_RESULT_VAR (result, val, T1, x, T2, y);
unsigned int precision = get_precision (result);
@@ -2419,11 +2447,24 @@ wi::add (const T1 &x, const T2 &y, signop sgn, bool *overflow)
unsigned HOST_WIDE_INT yl = yi.ulow ();
unsigned HOST_WIDE_INT resultl = xl + yl;
if (sgn == SIGNED)
- *overflow = (((resultl ^ xl) & (resultl ^ yl))
- >> (precision - 1)) & 1;
+ {
+ if ((((resultl ^ xl) & (resultl ^ yl))
+ >> (precision - 1)) & 1)
+ {
+ if (xl > resultl)
+ *overflow = OVF_UNDERFLOW;
+ else if (xl < resultl)
+ *overflow = OVF_OVERFLOW;
+ else
+ *overflow = OVF_NONE;
+ }
+ else
+ *overflow = OVF_NONE;
+ }
else
*overflow = ((resultl << (HOST_BITS_PER_WIDE_INT - precision))
- < (xl << (HOST_BITS_PER_WIDE_INT - precision)));
+ < (xl << (HOST_BITS_PER_WIDE_INT - precision)))
+ ? OVF_OVERFLOW : OVF_NONE;
val[0] = resultl;
result.set_len (1);
}
@@ -2480,7 +2521,7 @@ wi::sub (const T1 &x, const T2 &y)
and indicate in *OVERFLOW whether the operation overflowed. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::sub (const T1 &x, const T2 &y, signop sgn, bool *overflow)
+wi::sub (const T1 &x, const T2 &y, signop sgn, overflow_type *overflow)
{
WI_BINARY_RESULT_VAR (result, val, T1, x, T2, y);
unsigned int precision = get_precision (result);
@@ -2492,10 +2533,23 @@ wi::sub (const T1 &x, const T2 &y, signop sgn, bool *overflow)
unsigned HOST_WIDE_INT yl = yi.ulow ();
unsigned HOST_WIDE_INT resultl = xl - yl;
if (sgn == SIGNED)
- *overflow = (((xl ^ yl) & (resultl ^ xl)) >> (precision - 1)) & 1;
+ {
+ if ((((xl ^ yl) & (resultl ^ xl)) >> (precision - 1)) & 1)
+ {
+ if (xl > yl)
+ *overflow = OVF_UNDERFLOW;
+ else if (xl < yl)
+ *overflow = OVF_OVERFLOW;
+ else
+ *overflow = OVF_NONE;
+ }
+ else
+ *overflow = OVF_NONE;
+ }
else
*overflow = ((resultl << (HOST_BITS_PER_WIDE_INT - precision))
- > (xl << (HOST_BITS_PER_WIDE_INT - precision)));
+ > (xl << (HOST_BITS_PER_WIDE_INT - precision)))
+ ? OVF_UNDERFLOW : OVF_NONE;
val[0] = resultl;
result.set_len (1);
}
@@ -2530,7 +2584,7 @@ wi::mul (const T1 &x, const T2 &y)
and indicate in *OVERFLOW whether the operation overflowed. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::mul (const T1 &x, const T2 &y, signop sgn, bool *overflow)
+wi::mul (const T1 &x, const T2 &y, signop sgn, overflow_type *overflow)
{
WI_BINARY_RESULT_VAR (result, val, T1, x, T2, y);
unsigned int precision = get_precision (result);
@@ -2546,16 +2600,16 @@ wi::mul (const T1 &x, const T2 &y, signop sgn, bool *overflow)
*OVERFLOW whether the operation overflowed. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::smul (const T1 &x, const T2 &y, bool *overflow)
+wi::smul (const T1 &x, const T2 &y, overflow_type *overflow)
{
return mul (x, y, SIGNED, overflow);
}
/* Return X * Y, treating both X and Y as unsigned values. Indicate in
- *OVERFLOW whether the operation overflowed. */
+ *OVERFLOW if the result overflows. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::umul (const T1 &x, const T2 &y, bool *overflow)
+wi::umul (const T1 &x, const T2 &y, overflow_type *overflow)
{
return mul (x, y, UNSIGNED, overflow);
}
@@ -2581,7 +2635,7 @@ wi::mul_high (const T1 &x, const T2 &y, signop sgn)
overflows. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::div_trunc (const T1 &x, const T2 &y, signop sgn, bool *overflow)
+wi::div_trunc (const T1 &x, const T2 &y, signop sgn, overflow_type *overflow)
{
WI_BINARY_RESULT_VAR (quotient, quotient_val, T1, x, T2, y);
unsigned int precision = get_precision (quotient);
@@ -2616,7 +2670,7 @@ wi::udiv_trunc (const T1 &x, const T2 &y)
overflows. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::div_floor (const T1 &x, const T2 &y, signop sgn, bool *overflow)
+wi::div_floor (const T1 &x, const T2 &y, signop sgn, overflow_type *overflow)
{
WI_BINARY_RESULT_VAR (quotient, quotient_val, T1, x, T2, y);
WI_BINARY_RESULT_VAR (remainder, remainder_val, T1, x, T2, y);
@@ -2658,7 +2712,7 @@ wi::udiv_floor (const T1 &x, const T2 &y)
overflows. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::div_ceil (const T1 &x, const T2 &y, signop sgn, bool *overflow)
+wi::div_ceil (const T1 &x, const T2 &y, signop sgn, overflow_type *overflow)
{
WI_BINARY_RESULT_VAR (quotient, quotient_val, T1, x, T2, y);
WI_BINARY_RESULT_VAR (remainder, remainder_val, T1, x, T2, y);
@@ -2691,7 +2745,7 @@ wi::udiv_ceil (const T1 &x, const T2 &y)
in *OVERFLOW if the result overflows. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::div_round (const T1 &x, const T2 &y, signop sgn, bool *overflow)
+wi::div_round (const T1 &x, const T2 &y, signop sgn, overflow_type *overflow)
{
WI_BINARY_RESULT_VAR (quotient, quotient_val, T1, x, T2, y);
WI_BINARY_RESULT_VAR (remainder, remainder_val, T1, x, T2, y);
@@ -2779,7 +2833,7 @@ wi::gcd (const T1 &a, const T2 &b, signop sgn)
in *OVERFLOW if the division overflows. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::mod_trunc (const T1 &x, const T2 &y, signop sgn, bool *overflow)
+wi::mod_trunc (const T1 &x, const T2 &y, signop sgn, overflow_type *overflow)
{
WI_BINARY_RESULT_VAR (remainder, remainder_val, T1, x, T2, y);
unsigned int precision = get_precision (remainder);
@@ -2818,7 +2872,7 @@ wi::umod_trunc (const T1 &x, const T2 &y)
in *OVERFLOW if the division overflows. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::mod_floor (const T1 &x, const T2 &y, signop sgn, bool *overflow)
+wi::mod_floor (const T1 &x, const T2 &y, signop sgn, overflow_type *overflow)
{
WI_BINARY_RESULT_VAR (quotient, quotient_val, T1, x, T2, y);
WI_BINARY_RESULT_VAR (remainder, remainder_val, T1, x, T2, y);
@@ -2854,7 +2908,7 @@ wi::umod_floor (const T1 &x, const T2 &y)
in *OVERFLOW if the division overflows. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::mod_ceil (const T1 &x, const T2 &y, signop sgn, bool *overflow)
+wi::mod_ceil (const T1 &x, const T2 &y, signop sgn, overflow_type *overflow)
{
WI_BINARY_RESULT_VAR (quotient, quotient_val, T1, x, T2, y);
WI_BINARY_RESULT_VAR (remainder, remainder_val, T1, x, T2, y);
@@ -2880,7 +2934,7 @@ wi::mod_ceil (const T1 &x, const T2 &y, signop sgn, bool *overflow)
given by SGN. Indicate in *OVERFLOW if the division overflows. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
-wi::mod_round (const T1 &x, const T2 &y, signop sgn, bool *overflow)
+wi::mod_round (const T1 &x, const T2 &y, signop sgn, overflow_type *overflow)
{
WI_BINARY_RESULT_VAR (quotient, quotient_val, T1, x, T2, y);
WI_BINARY_RESULT_VAR (remainder, remainder_val, T1, x, T2, y);
@@ -3395,4 +3449,18 @@ wi::set_bit_in_zero (unsigned int bit)
return shifted_mask <T> (bit, 1, false);
}
+/* Accumulate a set of overflows into OVERFLOW. */
+
+static inline void
+wi::accumulate_overflow (wi::overflow_type &overflow,
+ wi::overflow_type suboverflow)
+{
+ if (!suboverflow)
+ return;
+ if (!overflow)
+ overflow = suboverflow;
+ else if (overflow != suboverflow)
+ overflow = wi::OVF_UNKNOWN;
+}
+
#endif /* WIDE_INT_H */