I am testing the following patch to remove the endless recursion between rshift_double and lshift_double trying to make their signed count argument positive by simple negation. I opted to make rshift_double private because it is the deprecated interface and is no longer used.
Bootstrap and regtest running on x86_64-unknown-linux-gnu. Richard. 2012-03-28 Richard Guenther <rguent...@suse.de> 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. Index: gcc/double-int.c =================================================================== *** gcc/double-int.c (revision 185911) --- gcc/double-int.c (working copy) *************** mul_double_with_sign (unsigned HOST_WIDE *** 186,209 **** 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; --- 186,207 ---- return (*hv < 0 ? ~(toplow & tophigh) : toplow | tophigh) != 0; } ! /* 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. */ ! 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; ! signmask = (arith ! ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1)) ! : 0); if (SHIFT_COUNT_TRUNCATED) count %= prec; *************** lshift_double (unsigned HOST_WIDE_INT l1 *** 217,277 **** } 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. 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, 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); - if (SHIFT_COUNT_TRUNCATED) count %= prec; --- 215,272 ---- } else if (count >= HOST_BITS_PER_WIDE_INT) { ! *hv = 0; ! *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT); } else { ! *hv = (unsigned HOST_WIDE_INT) h1 >> count; ! *lv = ((l1 >> count) ! | ((unsigned HOST_WIDE_INT) h1 ! << (HOST_BITS_PER_WIDE_INT - count - 1) << 1)); } ! /* Zero / 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) ; ! else if ((prec - count) >= 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 - count)); ! *lv |= signmask << (prec - count); } } ! /* 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; *************** rshift_double (unsigned HOST_WIDE_INT l1 *** 284,319 **** } else if (count >= HOST_BITS_PER_WIDE_INT) { ! *hv = 0; ! *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT); } else { ! *hv = (unsigned HOST_WIDE_INT) h1 >> count; ! *lv = ((l1 >> count) ! | ((unsigned HOST_WIDE_INT) h1 ! << (HOST_BITS_PER_WIDE_INT - count - 1) << 1)); } ! /* Zero / 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) ; ! else if ((prec - count) >= 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 - count)); ! *lv |= signmask << (prec - count); } } --- 279,313 ---- } 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; } } *************** double_int *** 895,901 **** 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); return ret; } --- 889,895 ---- double_int_rshift (double_int a, HOST_WIDE_INT count, unsigned int prec, bool arith) { double_int ret; ! lshift_double (a.low, a.high, -count, prec, &ret.low, &ret.high, arith); return ret; } Index: gcc/double-int.h =================================================================== *** gcc/double-int.h (revision 185911) --- gcc/double-int.h (working copy) *************** extern int mul_double_with_sign (unsigne *** 300,308 **** 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 *, --- 300,305 ----