diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e988df50c3a..0c2d199c54d 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 834eaf9d6c2..0f954425093 100644 --- a/gcc/double-int.c +++ b/gcc/double-int.c @@ -186,88 +186,19 @@ 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. - 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) -{ - unsigned HOST_WIDE_INT signmask; - - if (count < 0) - { - rshift_double (l1, h1, -count, prec, lv, hv, arith); - return; - } - - if (SHIFT_COUNT_TRUNCATED) - count %= prec; - - if (count >= 2 * HOST_BITS_PER_WIDE_INT) - { - /* Shifting by the host word size is undefined according to the - ANSI standard, so we must handle this as a special case. */ - *hv = 0; - *lv = 0; - } - else if (count >= HOST_BITS_PER_WIDE_INT) - { - *hv = l1 << (count - HOST_BITS_PER_WIDE_INT); - *lv = 0; - } - else - { - *hv = (((unsigned HOST_WIDE_INT) h1 << count) - | (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1)); - *lv = l1 << count; - } - - /* 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); - - if (prec >= 2 * HOST_BITS_PER_WIDE_INT) - ; - else if (prec >= 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); - *lv |= signmask << prec; - } -} - /* Shift the doubleword integer in L1, H1 right by COUNT places - keeping only PREC bits of result. Shift left if COUNT is negative. - ARITH nonzero specifies arithmetic shifting; otherwise use logical shift. + 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 +static void rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, - HOST_WIDE_INT count, unsigned int prec, + 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) - { - lshift_double (l1, h1, -count, prec, lv, hv, arith); - return; - } - signmask = (arith ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1)) : 0); @@ -317,6 +248,69 @@ rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, } } +/* 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 +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 signmask; + + if (count < 0) + { + rshift_double (l1, h1, absu_hwi (count), prec, lv, hv, arith); + return; + } + + if (SHIFT_COUNT_TRUNCATED) + count %= prec; + + if (count >= 2 * HOST_BITS_PER_WIDE_INT) + { + /* Shifting by the host word size is undefined according to the + ANSI standard, so we must handle this as a special case. */ + *hv = 0; + *lv = 0; + } + else if (count >= HOST_BITS_PER_WIDE_INT) + { + *hv = l1 << (count - HOST_BITS_PER_WIDE_INT); + *lv = 0; + } + else + { + *hv = (((unsigned HOST_WIDE_INT) h1 << count) + | (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1)); + *lv = l1 << count; + } + + /* 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); + + if (prec >= 2 * HOST_BITS_PER_WIDE_INT) + ; + else if (prec >= 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); + *lv |= signmask << prec; + } +} + /* Divide doubleword integer LNUM, HNUM by doubleword integer LDEN, HDEN for a quotient (stored in *LQUO, *HQUO) and remainder (in *LREM, *HREM). CODE is a tree code for a kind of division, one of @@ -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 6d1555111d3..408ed92b8a1 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 *,