From 477fcae3e8156d1cdcf7978595c3cff7617610b8 Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Thu, 29 Mar 2012 08:27:04 +0000 Subject: [PATCH] re PR middle-end/50708 (Infinite loop between rshift_double and lshift_double if count is LONG_MIN) 2012-03-29 Richard Guenther PR middle-end/50708 * double-int.h (rshift_double): Remove. * double-int.c (lshift_double): Use absu_hwi to make count positive. (rshift_double): Make static, take unsigned count argument, remove handling of negative count argument. (double_int_rshift): Dispatch to lshift_double. From-SVN: r185951 --- gcc/ChangeLog | 10 +++++ gcc/double-int.c | 112 ++++++++++++++++++++++++++----------------------------- gcc/double-int.h | 3 -- 3 files changed, 63 insertions(+), 62 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e988df5..0c2d199 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2012-03-29 Richard Guenther + + PR middle-end/50708 + * double-int.h (rshift_double): Remove. + * double-int.c (lshift_double): Use absu_hwi to make count + positive. + (rshift_double): Make static, take unsigned count argument, + remove handling of negative count argument. + (double_int_rshift): Dispatch to lshift_double. + 2012-03-28 H.J. Lu * config/i386/biarch64.h (TARGET_64BIT_DEFAULT): Add diff --git a/gcc/double-int.c b/gcc/double-int.c index 834eaf9..0f95442 100644 --- a/gcc/double-int.c +++ b/gcc/double-int.c @@ -186,24 +186,22 @@ mul_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, return (*hv < 0 ? ~(toplow & tophigh) : toplow | tophigh) != 0; } -/* Shift the doubleword integer in L1, H1 left by COUNT places - keeping only PREC bits of result. - Shift right if COUNT is negative. - ARITH nonzero specifies arithmetic shifting; otherwise use logical shift. +/* Shift the doubleword integer in L1, H1 right by COUNT places + keeping only PREC bits of result. ARITH nonzero specifies + arithmetic shifting; otherwise use logical shift. Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */ -void -lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, - HOST_WIDE_INT count, unsigned int prec, - unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, bool arith) +static void +rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, + unsigned HOST_WIDE_INT count, unsigned int prec, + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, + bool arith) { unsigned HOST_WIDE_INT signmask; - if (count < 0) - { - rshift_double (l1, h1, -count, prec, lv, hv, arith); - return; - } + signmask = (arith + ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1)) + : 0); if (SHIFT_COUNT_TRUNCATED) count %= prec; @@ -217,61 +215,58 @@ lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, } else if (count >= HOST_BITS_PER_WIDE_INT) { - *hv = l1 << (count - HOST_BITS_PER_WIDE_INT); - *lv = 0; + *hv = 0; + *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT); } else { - *hv = (((unsigned HOST_WIDE_INT) h1 << count) - | (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1)); - *lv = l1 << count; + *hv = (unsigned HOST_WIDE_INT) h1 >> count; + *lv = ((l1 >> count) + | ((unsigned HOST_WIDE_INT) h1 + << (HOST_BITS_PER_WIDE_INT - count - 1) << 1)); } - /* Sign extend all bits that are beyond the precision. */ - - signmask = -((prec > HOST_BITS_PER_WIDE_INT - ? ((unsigned HOST_WIDE_INT) *hv - >> (prec - HOST_BITS_PER_WIDE_INT - 1)) - : (*lv >> (prec - 1))) & 1); + /* Zero / sign extend all bits that are beyond the precision. */ - if (prec >= 2 * HOST_BITS_PER_WIDE_INT) + if (count >= (HOST_WIDE_INT)prec) + { + *hv = signmask; + *lv = signmask; + } + else if ((prec - count) >= 2 * HOST_BITS_PER_WIDE_INT) ; - else if (prec >= HOST_BITS_PER_WIDE_INT) + else if ((prec - count) >= HOST_BITS_PER_WIDE_INT) { - *hv &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT)); - *hv |= signmask << (prec - HOST_BITS_PER_WIDE_INT); + *hv &= ~((HOST_WIDE_INT) (-1) << (prec - count - HOST_BITS_PER_WIDE_INT)); + *hv |= signmask << (prec - count - HOST_BITS_PER_WIDE_INT); } else { *hv = signmask; - *lv &= ~((unsigned HOST_WIDE_INT) (-1) << prec); - *lv |= signmask << prec; + *lv &= ~((unsigned HOST_WIDE_INT) (-1) << (prec - count)); + *lv |= signmask << (prec - count); } } -/* Shift the doubleword integer in L1, H1 right by COUNT places - keeping only PREC bits of result. Shift left if COUNT is negative. +/* Shift the doubleword integer in L1, H1 left by COUNT places + keeping only PREC bits of result. + Shift right if COUNT is negative. ARITH nonzero specifies arithmetic shifting; otherwise use logical shift. Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */ void -rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, +lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, HOST_WIDE_INT count, unsigned int prec, - unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, - bool arith) + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, bool arith) { unsigned HOST_WIDE_INT signmask; if (count < 0) { - lshift_double (l1, h1, -count, prec, lv, hv, arith); + rshift_double (l1, h1, absu_hwi (count), prec, lv, hv, arith); return; } - signmask = (arith - ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1)) - : 0); - if (SHIFT_COUNT_TRUNCATED) count %= prec; @@ -284,36 +279,35 @@ rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, } else if (count >= HOST_BITS_PER_WIDE_INT) { - *hv = 0; - *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT); + *hv = l1 << (count - HOST_BITS_PER_WIDE_INT); + *lv = 0; } else { - *hv = (unsigned HOST_WIDE_INT) h1 >> count; - *lv = ((l1 >> count) - | ((unsigned HOST_WIDE_INT) h1 - << (HOST_BITS_PER_WIDE_INT - count - 1) << 1)); + *hv = (((unsigned HOST_WIDE_INT) h1 << count) + | (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1)); + *lv = l1 << count; } - /* Zero / sign extend all bits that are beyond the precision. */ + /* Sign extend all bits that are beyond the precision. */ - if (count >= (HOST_WIDE_INT)prec) - { - *hv = signmask; - *lv = signmask; - } - else if ((prec - count) >= 2 * HOST_BITS_PER_WIDE_INT) + signmask = -((prec > HOST_BITS_PER_WIDE_INT + ? ((unsigned HOST_WIDE_INT) *hv + >> (prec - HOST_BITS_PER_WIDE_INT - 1)) + : (*lv >> (prec - 1))) & 1); + + if (prec >= 2 * HOST_BITS_PER_WIDE_INT) ; - else if ((prec - count) >= HOST_BITS_PER_WIDE_INT) + else if (prec >= HOST_BITS_PER_WIDE_INT) { - *hv &= ~((HOST_WIDE_INT) (-1) << (prec - count - HOST_BITS_PER_WIDE_INT)); - *hv |= signmask << (prec - count - HOST_BITS_PER_WIDE_INT); + *hv &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT)); + *hv |= signmask << (prec - HOST_BITS_PER_WIDE_INT); } else { *hv = signmask; - *lv &= ~((unsigned HOST_WIDE_INT) (-1) << (prec - count)); - *lv |= signmask << (prec - count); + *lv &= ~((unsigned HOST_WIDE_INT) (-1) << prec); + *lv |= signmask << prec; } } @@ -895,7 +889,7 @@ double_int double_int_rshift (double_int a, HOST_WIDE_INT count, unsigned int prec, bool arith) { double_int ret; - rshift_double (a.low, a.high, count, prec, &ret.low, &ret.high, arith); + lshift_double (a.low, a.high, -count, prec, &ret.low, &ret.high, arith); return ret; } diff --git a/gcc/double-int.h b/gcc/double-int.h index 6d15551..408ed92 100644 --- a/gcc/double-int.h +++ b/gcc/double-int.h @@ -300,9 +300,6 @@ extern int mul_double_with_sign (unsigned HOST_WIDE_INT, HOST_WIDE_INT, extern void lshift_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT, HOST_WIDE_INT, unsigned int, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, bool); -extern void rshift_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT, - HOST_WIDE_INT, unsigned int, - unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, bool); extern int div_and_round_double (unsigned, int, unsigned HOST_WIDE_INT, HOST_WIDE_INT, unsigned HOST_WIDE_INT, HOST_WIDE_INT, unsigned HOST_WIDE_INT *, -- 2.7.4