diff options
Diffstat (limited to 'gcc/wide-int.h')
-rw-r--r-- | gcc/wide-int.h | 150 |
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 */ |