removed all knowledge of SHIFT_COUNT_TRUNCATED from wide-int
both Richard Biener and Richard Sandiford had commented negatively about this.
fixed bug with wide-int::fits_uhwi_p. kenny
Index: gcc/fold-const.c =================================================================== --- gcc/fold-const.c (revision 201985) +++ gcc/fold-const.c (working copy) @@ -992,9 +992,9 @@ int_const_binop_1 (enum tree_code code, /* It's unclear from the C standard whether shifts can overflow. The following code ignores overflow; perhaps a C standard interpretation ruling is needed. */ - res = op1.rshift (arg2, sign, GET_MODE_BITSIZE (TYPE_MODE (type)), TRUNC); + res = op1.rshift (arg2, sign, GET_MODE_BITSIZE (TYPE_MODE (type))); else - res = op1.lshift (arg2, GET_MODE_BITSIZE (TYPE_MODE (type)), TRUNC); + res = op1.lshift (arg2, GET_MODE_BITSIZE (TYPE_MODE (type))); break; case RROTATE_EXPR: Index: gcc/simplify-rtx.c =================================================================== --- gcc/simplify-rtx.c (revision 201985) +++ gcc/simplify-rtx.c (working copy) @@ -3507,9 +3507,7 @@ rtx simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode, rtx op0, rtx op1) { -#if TARGET_SUPPORTS_WIDE_INT == 0 unsigned int width = GET_MODE_PRECISION (mode); -#endif if (VECTOR_MODE_P (mode) && code != VEC_CONCAT @@ -3787,40 +3785,45 @@ simplify_const_binary_operation (enum rt break; case LSHIFTRT: - if (wide_int (std::make_pair (op1, mode)).neg_p ()) - return NULL_RTX; - - result = wop0.rshiftu (pop1, bitsize, TRUNC); - break; - case ASHIFTRT: - if (wide_int (std::make_pair (op1, mode)).neg_p ()) - return NULL_RTX; - - result = wop0.rshifts (pop1, bitsize, TRUNC); - break; - case ASHIFT: - if (wide_int (std::make_pair (op1, mode)).neg_p ()) - return NULL_RTX; - - result = wop0.lshift (pop1, bitsize, TRUNC); - break; - case ROTATE: - if (wide_int (std::make_pair (op1, mode)).neg_p ()) - return NULL_RTX; - - result = wop0.lrotate (pop1); - break; - case ROTATERT: - if (wide_int (std::make_pair (op1, mode)).neg_p ()) - return NULL_RTX; + { + wide_int wop1 = pop1; + if (wop1.neg_p ()) + return NULL_RTX; - result = wop0.rrotate (pop1); - break; + if (SHIFT_COUNT_TRUNCATED) + wop1 = wop1.umod_trunc (width); + switch (code) + { + case LSHIFTRT: + result = wop0.rshiftu (wop1, bitsize); + break; + + case ASHIFTRT: + result = wop0.rshifts (wop1, bitsize); + break; + + case ASHIFT: + result = wop0.lshift (wop1, bitsize); + break; + + case ROTATE: + result = wop0.lrotate (wop1); + break; + + case ROTATERT: + result = wop0.rrotate (wop1); + break; + + default: + gcc_unreachable (); + } + break; + } default: return NULL_RTX; } Index: gcc/wide-int.cc =================================================================== --- gcc/wide-int.cc (revision 201985) +++ gcc/wide-int.cc (working copy) @@ -2404,7 +2404,12 @@ wide_int_ro::divmod_internal_2 (unsigned /* Do a truncating divide DIVISOR into DIVIDEND. The result is the - same size as the operands. SIGN is either SIGNED or UNSIGNED. */ + same size as the operands. SIGN is either SIGNED or UNSIGNED. If + COMPUTE_QUOTIENT is set, the quotient is computed and returned. If + it is not set, the result is undefined. If COMPUTE_REMAINDER is + set, the remaineder is returned in remainder. If it is not set, + the remainder is undefined. If OFLOW is not null, it is set to the + overflow value. */ wide_int_ro wide_int_ro::divmod_internal (bool compute_quotient, const HOST_WIDE_INT *dividend, @@ -2470,6 +2475,10 @@ wide_int_ro::divmod_internal (bool compu quotient.precision = dividend_prec; remainder->precision = dividend_prec; + /* Initialize the incoming overflow if it has been provided. */ + if (oflow) + *oflow = false; + /* If overflow is set, just get out. There will only be grief by continuing. */ if (overflow) Index: gcc/wide-int.h =================================================================== --- gcc/wide-int.h (revision 201995) +++ gcc/wide-int.h (working copy) @@ -259,19 +259,6 @@ const int addr_max_bitsize = 64; const int addr_max_precision = ((addr_max_bitsize + 4 + HOST_BITS_PER_WIDE_INT - 1) & ~(HOST_BITS_PER_WIDE_INT - 1)); -enum ShiftOp { - NONE, - /* There are two uses for the wide-int shifting functions. The - first use is as an emulation of the target hardware. The - second use is as service routines for other optimizations. The - first case needs to be identified by passing TRUNC as the value - of ShiftOp so that shift amount is properly handled according to the - SHIFT_COUNT_TRUNCATED flag. For the second case, the shift - amount is always truncated by the bytesize of the mode of - THIS. */ - TRUNC -}; - /* This is used to bundle an rtx and a mode together so that the pair can be used as the second operand of a wide int expression. If we ever put modes into rtx integer constants, this should go away and @@ -661,7 +648,7 @@ public: HOST_WIDE_INT extract_to_hwi (int, int) const; template <typename T> - wide_int_ro lshift (const T &, unsigned int = 0, ShiftOp = NONE) const; + wide_int_ro lshift (const T &, unsigned int = 0) const; template <typename T> wide_int_ro lshift_widen (const T &, unsigned int) const; @@ -672,14 +659,13 @@ public: wide_int_ro lrotate (unsigned HOST_WIDE_INT, unsigned int = 0) const; template <typename T> - wide_int_ro rshift (const T &, signop, unsigned int = 0, - ShiftOp = NONE) const; + wide_int_ro rshift (const T &, signop, unsigned int = 0) const; template <typename T> - wide_int_ro rshiftu (const T &, unsigned int = 0, ShiftOp = NONE) const; + wide_int_ro rshiftu (const T &, unsigned int = 0) const; template <typename T> - wide_int_ro rshifts (const T &, unsigned int = 0, ShiftOp = NONE) const; + wide_int_ro rshifts (const T &, unsigned int = 0) const; template <typename T> wide_int_ro rrotate (const T &, unsigned int = 0) const; @@ -749,13 +735,11 @@ private: signop, wide_int_ro *, bool, bool *); /* Private utility routines. */ + int trunc_shift (const HOST_WIDE_INT *cnt, unsigned int bitsize) const; wide_int_ro decompress (unsigned int, unsigned int) const; void canonize (); static wide_int_ro from_rtx (const rtx_mode_t); - int trunc_shift (const HOST_WIDE_INT *, unsigned int, unsigned int, - ShiftOp) const; - template <typename T> static bool top_bit_set (T); @@ -1650,7 +1634,10 @@ wide_int_ro::fits_shwi_p () const inline bool wide_int_ro::fits_uhwi_p () const { - return (len == 1 && val[0] >= 0) || (len == 2 && val[1] == 0); + return (precision <= HOST_BITS_PER_WIDE_INT) + || (len == 1 && val[0] >= 0) + || (len == 2 && (precision >= 2 * HOST_BITS_PER_WIDE_INT) && (val[1] == 0)) + || (len == 2 && (sext_hwi (val[1], precision & (HOST_BITS_PER_WIDE_INT - 1)) == 0)); } /* Return the signed or unsigned min of THIS and C. */ @@ -2358,8 +2345,6 @@ wide_int_ro::div_trunc (const T &c, sign unsigned int cl; unsigned int p1, p2; - if (overflow) - *overflow = false; p1 = precision; s = to_shwi1 (ws, &cl, &p2, c); check_precision (&p1, &p2, false, true); @@ -2399,8 +2384,6 @@ wide_int_ro::div_floor (const T &c, sign unsigned int cl; unsigned int p1, p2; - if (overflow) - *overflow = false; p1 = precision; s = to_shwi1 (ws, &cl, &p2, c); check_precision (&p1, &p2, false, true); @@ -2440,8 +2423,6 @@ wide_int_ro::div_ceil (const T &c, signo unsigned int cl; unsigned int p1, p2; - if (overflow) - *overflow = false; p1 = precision; s = to_shwi1 (ws, &cl, &p2, c); check_precision (&p1, &p2, false, true); @@ -2469,8 +2450,6 @@ wide_int_ro::div_round (const T &c, sign unsigned int cl; unsigned int p1, p2; - if (overflow) - *overflow = false; p1 = precision; s = to_shwi1 (ws, &cl, &p2, c); check_precision (&p1, &p2, false, true); @@ -2544,7 +2523,7 @@ wide_int_ro::udivmod_trunc (const T &c, /* Divide DIVISOR into THIS. The remainder is also produced in REMAINDER. The result is the same size as the operands. - The sign is specified in SGN. The output is floor truncated. */ + The sign is specified in SGN. The outputs is floor truncated. */ template <typename T> inline wide_int_ro wide_int_ro::divmod_floor (const T &c, wide_int_ro *remainder, @@ -2579,9 +2558,10 @@ wide_int_ro::sdivmod_floor (const T &c, } /* Divide DIVISOR into THIS producing the remainder. The result is - the same size as the operands. The sign is specified in SGN. - The output is truncated. If the pointer to OVERFLOW is not 0, - OVERFLOW is set to true if the result overflows, false otherwise. */ + the same size as the operands. The sign is specified in SGN. The + output is adjusted to be compatible with truncating divide. If the + pointer to OVERFLOW is not 0, OVERFLOW is set to true if the result + overflows, false otherwise. */ template <typename T> inline wide_int_ro wide_int_ro::mod_trunc (const T &c, signop sgn, bool *overflow) const @@ -2592,8 +2572,6 @@ wide_int_ro::mod_trunc (const T &c, sign unsigned int cl; unsigned int p1, p2; - if (overflow) - *overflow = false; p1 = precision; s = to_shwi1 (ws, &cl, &p2, c); check_precision (&p1, &p2, false, true); @@ -2620,9 +2598,9 @@ wide_int_ro::umod_trunc (const T &c) con } /* Divide DIVISOR into THIS producing the remainder. The result is - the same size as the operands. The sign is specified in SGN. - The output is floor truncated. OVERFLOW is set to true if the - result overflows, false otherwise. */ + the same size as the operands. The sign is specified in SGN. The + output is adjusted to be compatible with floor divide. OVERFLOW is + set to true if the result overflows, false otherwise. */ template <typename T> inline wide_int_ro wide_int_ro::mod_floor (const T &c, signop sgn, bool *overflow) const @@ -2634,8 +2612,6 @@ wide_int_ro::mod_floor (const T &c, sign unsigned int cl; unsigned int p1, p2; - if (overflow) - *overflow = false; p1 = precision; s = to_shwi1 (ws, &cl, &p2, c); check_precision (&p1, &p2, false, true); @@ -2657,9 +2633,10 @@ wide_int_ro::umod_floor (const T &c) con } /* Divide DIVISOR into THIS producing the remainder. The result is - the same size as the operands. The sign is specified in SGN. - The output is ceil truncated. If the pointer to OVERFLOW is not 0, - OVERFLOW is set to true if the result overflows, false otherwise. */ + the same size as the operands. The sign is specified in SGN. The + output is adjusted to be compatible with ceil divide. If the + pointer to OVERFLOW is not 0, OVERFLOW is set to true if the result + overflows, false otherwise. */ template <typename T> inline wide_int_ro wide_int_ro::mod_ceil (const T &c, signop sgn, bool *overflow) const @@ -2671,8 +2648,6 @@ wide_int_ro::mod_ceil (const T &c, signo unsigned int cl; unsigned int p1, p2; - if (overflow) - *overflow = false; p1 = precision; s = to_shwi1 (ws, &cl, &p2, c); check_precision (&p1, &p2, false, true); @@ -2686,9 +2661,9 @@ wide_int_ro::mod_ceil (const T &c, signo } /* Divide DIVISOR into THIS producing the remainder. The result is - the same size as the operands. The sign is specified in SGN. - The output is round truncated. OVERFLOW is set to true if the - result overflows, false otherwise. */ + the same size as the operands. The sign is specified in SGN. The + output is adjusted to be compatible with rounding divide. OVERFLOW + is set to true if the result overflows, false otherwise. */ template <typename T> inline wide_int_ro wide_int_ro::mod_round (const T &c, signop sgn, bool *overflow) const @@ -2700,8 +2675,6 @@ wide_int_ro::mod_round (const T &c, sign unsigned int cl; unsigned int p1, p2; - if (overflow) - *overflow = false; p1 = precision; s = to_shwi1 (ws, &cl, &p2, c); check_precision (&p1, &p2, false, true); @@ -2738,11 +2711,10 @@ wide_int_ro::mod_round (const T &c, sign } /* Left shift THIS by C. C must be non-negative. BITSIZE is the - width of *THIS used for truncating the shift amount. See the - definition of Op.TRUNC for how to set TRUNC_OP. */ + width of *THIS used for truncating the shift amount. */ template <typename T> inline wide_int_ro -wide_int_ro::lshift (const T &c, unsigned int bitsize, ShiftOp trunc_op) const +wide_int_ro::lshift (const T &c, unsigned int bitsize) const { wide_int_ro result; HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS]; @@ -2754,7 +2726,7 @@ wide_int_ro::lshift (const T &c, unsigne gcc_checking_assert (precision); - shift = trunc_shift (s, cl, bitsize, trunc_op); + shift = trunc_shift (s, bitsize); if (shift == -1) result = wide_int_ro::zero (precision); else if (shift == 0) @@ -2857,25 +2829,23 @@ wide_int_ro::lrotate (unsigned HOST_WIDE } /* Right shift THIS by C. BITSIZE is the width of *THIS used for - truncating the shift amount. SGN indicates the sign. TRUNC_OP - indicates the truncation option. C must be non-negative. */ + truncating the shift amount. SGN indicates the sign. C must be + non-negative. */ template <typename T> inline wide_int_ro -wide_int_ro::rshift (const T &c, signop sgn, unsigned int bitsize, - ShiftOp trunc_op) const +wide_int_ro::rshift (const T &c, signop sgn, unsigned int bitsize) const { if (sgn == UNSIGNED) - return rshiftu (c, bitsize, trunc_op); + return rshiftu (c, bitsize); else - return rshifts (c, bitsize, trunc_op); + return rshifts (c, bitsize); } /* Unsigned right shift THIS by C. C must be non-negative. BITSIZE - is width of *THIS used for truncating the shift amount. See the - definition of Op.TRUNC for how to set TRUNC_OP. */ + is width of *THIS used for truncating the shift amount. */ template <typename T> inline wide_int_ro -wide_int_ro::rshiftu (const T &c, unsigned int bitsize, ShiftOp trunc_op) const +wide_int_ro::rshiftu (const T &c, unsigned int bitsize) const { wide_int_ro result; HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS]; @@ -2885,7 +2855,7 @@ wide_int_ro::rshiftu (const T &c, unsign s = to_shwi2 (ws, &cl, c); gcc_checking_assert (precision); - shift = trunc_shift (s, cl, bitsize, trunc_op); + shift = trunc_shift (s, bitsize); if (shift == 0) result = *this; @@ -2914,11 +2884,10 @@ wide_int_ro::rshiftu (const T &c, unsign } /* Signed right shift THIS by C. C must be non-negative, BITSIZE is - the width of *THIS used for truncating the shift amount. See the - definition of Op.TRUNC for how to set TRUNC_OP. */ + the width of *THIS used for truncating the shift amount. */ template <typename T> inline wide_int_ro -wide_int_ro::rshifts (const T &c, unsigned int bitsize, ShiftOp trunc_op) const +wide_int_ro::rshifts (const T &c, unsigned int bitsize) const { wide_int_ro result; HOST_WIDE_INT ws[WIDE_INT_MAX_ELTS]; @@ -2928,7 +2897,7 @@ wide_int_ro::rshifts (const T &c, unsign s = to_shwi2 (ws, &cl, c); gcc_checking_assert (precision); - shift = trunc_shift (s, cl, bitsize, trunc_op); + shift = trunc_shift (s, bitsize); if (shift == 0) result = *this; @@ -3001,62 +2970,14 @@ wide_int_ro::rrotate (unsigned HOST_WIDE return result; } -/* If SHIFT_COUNT_TRUNCATED is defined, truncate CNT. - - At first look, the shift truncation code does not look right. - Shifts (and rotates) are done according to the precision of the - mode but the shift count is truncated according to the bitsize of - the mode. This is how real hardware works (Knuth's mix machine - is the only known exception to this rule, but it was never real). - - On an ideal machine, like Knuth's mix machine, a shift count is a - word long and all of the bits of that word are examined to - compute the shift amount. But on real hardware, especially on - machines with fast (single cycle shifts) that takes too long. - On these machines, the amount of time to perform a shift dictates - the cycle time of the machine so corners are cut to keep this - fast. A comparison of an entire 64 bit word would take something - like 6 gate delays before the shifting can even start. - - So real hardware only looks at a small part of the shift amount. - On IBM machines, this tends to be 1 more than what is necessary - to encode the shift amount. The rest of the world looks at only - the minimum number of bits. This means that only 3 gate delays - are necessary to set up the shifter. - - On the other hand, right shifts and rotates must be according to - the precision or the operation does not make any sense. - - This function is called in two contexts. If TRUNC_OP == TRUNC, - this function provides a count that matches the semantics of the - target machine depending on the value of SHIFT_COUNT_TRUNCATED. - Note that if SHIFT_COUNT_TRUNCATED is not defined, this function - may produce -1 as a value if the shift amount is greater than the - bitsize of the mode. -1 is a surrogate for a very large amount. - - If TRUNC_OP == NONE, then this function always truncates the shift - value to the bitsize because this shifting operation is a - function that is internal to GCC. */ +/* Truncate the value of the shift so that the value is within the + BITSIZE. */ inline int -wide_int_ro::trunc_shift (const HOST_WIDE_INT *cnt, - unsigned int len ATTRIBUTE_UNUSED, - unsigned int bitsize, ShiftOp trunc_op) const +wide_int_ro::trunc_shift (const HOST_WIDE_INT *cnt, unsigned int bitsize) const { gcc_checking_assert (cnt[0] >= 0); - if (trunc_op == TRUNC) - { - gcc_checking_assert (bitsize != 0); -#ifdef SHIFT_COUNT_TRUNCATED - return cnt[0] & (bitsize - 1); -#else - if (cnt[0] < bitsize && cnt[0] >= 0 && len == 1) - return cnt[0]; - else - return -1; -#endif - } - else if (bitsize == 0) + if (bitsize == 0) return cnt[0]; else return cnt[0] & (bitsize - 1); @@ -3477,20 +3398,19 @@ public: fixed_wide_int lrotate (unsigned HOST_WIDE_INT, unsigned int) const; template <typename T> - fixed_wide_int lshift (const T &, unsigned int = 0, ShiftOp = NONE) const; + fixed_wide_int lshift (const T &, unsigned int = 0) const; template <typename T> fixed_wide_int lshift_widen (const T &, unsigned int) const; template <typename T> - fixed_wide_int rshift (const T &, signop, unsigned int = 0, - ShiftOp = NONE) const; + fixed_wide_int rshift (const T &, signop, unsigned int = 0) const; template <typename T> - fixed_wide_int rshiftu (const T &, unsigned int = 0, ShiftOp = NONE) const; + fixed_wide_int rshiftu (const T &, unsigned int = 0) const; template <typename T> - fixed_wide_int rshifts (const T &, unsigned int = 0, ShiftOp = NONE) const; + fixed_wide_int rshifts (const T &, unsigned int = 0) const; template <typename T> fixed_wide_int rrotate (const T &, unsigned int) const; @@ -4026,10 +3946,9 @@ fixed_wide_int <bitsize>::lrotate (unsig template <int bitsize> template <typename T> inline fixed_wide_int <bitsize> -fixed_wide_int <bitsize>::lshift (const T &c, unsigned int bit_size, - ShiftOp z) const +fixed_wide_int <bitsize>::lshift (const T &c, unsigned int bit_size) const { - return wide_int_ro::lshift (c, bit_size, z); + return wide_int_ro::lshift (c, bit_size); } template <int bitsize> @@ -4044,28 +3963,28 @@ fixed_wide_int <bitsize>::lshift_widen ( template <int bitsize> template <typename T> inline fixed_wide_int <bitsize> -fixed_wide_int <bitsize>::rshift (const T &c, signop sgn, - unsigned int bit_size, ShiftOp z) const +fixed_wide_int <bitsize>::rshift (const T &c, signop sgn, + unsigned int bit_size) const { - return wide_int_ro::rshift (c, sgn, bit_size, z); + return wide_int_ro::rshift (c, sgn, bit_size); } template <int bitsize> template <typename T> inline fixed_wide_int <bitsize> -fixed_wide_int <bitsize>::rshiftu (const T &c, unsigned int bit_size, - ShiftOp z) const +fixed_wide_int <bitsize>::rshiftu (const T &c, + unsigned int bit_size) const { - return wide_int_ro::rshiftu (c, bit_size, z); + return wide_int_ro::rshiftu (c, bit_size); } template <int bitsize> template <typename T> inline fixed_wide_int <bitsize> -fixed_wide_int <bitsize>::rshifts (const T &c, unsigned int bit_size, - ShiftOp z) const +fixed_wide_int <bitsize>::rshifts (const T &c, + unsigned int bit_size) const { - return wide_int_ro::rshifts (c, bit_size, z); + return wide_int_ro::rshifts (c, bit_size); } template <int bitsize>