Commit 477fcae3 by Richard Guenther Committed by Richard Biener

re PR middle-end/50708 (Infinite loop between rshift_double and lshift_double if count is LONG_MIN)

2012-03-29  Richard Guenther  <rguenther@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.

From-SVN: r185951
parent 0b284728
2012-03-29 Richard Guenther <rguenther@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.
2012-03-28 H.J. Lu <hongjiu.lu@intel.com> 2012-03-28 H.J. Lu <hongjiu.lu@intel.com>
* config/i386/biarch64.h (TARGET_64BIT_DEFAULT): Add * config/i386/biarch64.h (TARGET_64BIT_DEFAULT): Add
......
...@@ -186,24 +186,22 @@ mul_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, ...@@ -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; return (*hv < 0 ? ~(toplow & tophigh) : toplow | tophigh) != 0;
} }
/* Shift the doubleword integer in L1, H1 left by COUNT places /* Shift the doubleword integer in L1, H1 right by COUNT places
keeping only PREC bits of result. keeping only PREC bits of result. ARITH nonzero specifies
Shift right if COUNT is negative. arithmetic shifting; otherwise use logical shift.
ARITH nonzero specifies arithmetic shifting; otherwise use logical shift.
Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */ Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */
void static void
lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, 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 *lv, HOST_WIDE_INT *hv,
bool arith)
{ {
unsigned HOST_WIDE_INT signmask; unsigned HOST_WIDE_INT signmask;
if (count < 0) signmask = (arith
{ ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1))
rshift_double (l1, h1, -count, prec, lv, hv, arith); : 0);
return;
}
if (SHIFT_COUNT_TRUNCATED) if (SHIFT_COUNT_TRUNCATED)
count %= prec; count %= prec;
...@@ -217,61 +215,58 @@ lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, ...@@ -217,61 +215,58 @@ lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
} }
else if (count >= HOST_BITS_PER_WIDE_INT) else if (count >= HOST_BITS_PER_WIDE_INT)
{ {
*hv = l1 << (count - HOST_BITS_PER_WIDE_INT); *hv = 0;
*lv = 0; *lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT);
} }
else else
{ {
*hv = (((unsigned HOST_WIDE_INT) h1 << count) *hv = (unsigned HOST_WIDE_INT) h1 >> count;
| (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1)); *lv = ((l1 >> 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. */ /* Zero / 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) 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 &= ~((HOST_WIDE_INT) (-1) << (prec - count - HOST_BITS_PER_WIDE_INT));
*hv |= signmask << (prec - HOST_BITS_PER_WIDE_INT); *hv |= signmask << (prec - count - HOST_BITS_PER_WIDE_INT);
} }
else else
{ {
*hv = signmask; *hv = signmask;
*lv &= ~((unsigned HOST_WIDE_INT) (-1) << prec); *lv &= ~((unsigned HOST_WIDE_INT) (-1) << (prec - count));
*lv |= signmask << prec; *lv |= signmask << (prec - count);
} }
} }
/* Shift the doubleword integer in L1, H1 right by COUNT places /* Shift the doubleword integer in L1, H1 left by COUNT places
keeping only PREC bits of result. Shift left if COUNT is negative. keeping only PREC bits of result.
Shift right if COUNT is negative.
ARITH nonzero specifies arithmetic shifting; otherwise use logical shift. ARITH nonzero specifies arithmetic shifting; otherwise use logical shift.
Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */ Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */
void 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, HOST_WIDE_INT count, unsigned int prec,
unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, bool arith)
bool arith)
{ {
unsigned HOST_WIDE_INT signmask; unsigned HOST_WIDE_INT signmask;
if (count < 0) if (count < 0)
{ {
lshift_double (l1, h1, -count, prec, lv, hv, arith); rshift_double (l1, h1, absu_hwi (count), prec, lv, hv, arith);
return; return;
} }
signmask = (arith
? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1))
: 0);
if (SHIFT_COUNT_TRUNCATED) if (SHIFT_COUNT_TRUNCATED)
count %= prec; count %= prec;
...@@ -284,36 +279,35 @@ rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, ...@@ -284,36 +279,35 @@ rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
} }
else if (count >= HOST_BITS_PER_WIDE_INT) else if (count >= HOST_BITS_PER_WIDE_INT)
{ {
*hv = 0; *hv = l1 << (count - HOST_BITS_PER_WIDE_INT);
*lv = (unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT); *lv = 0;
} }
else else
{ {
*hv = (unsigned HOST_WIDE_INT) h1 >> count; *hv = (((unsigned HOST_WIDE_INT) h1 << count)
*lv = ((l1 >> count) | (l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1));
| ((unsigned HOST_WIDE_INT) h1 *lv = l1 << count;
<< (HOST_BITS_PER_WIDE_INT - count - 1) << 1));
} }
/* 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) signmask = -((prec > HOST_BITS_PER_WIDE_INT
{ ? ((unsigned HOST_WIDE_INT) *hv
*hv = signmask; >> (prec - HOST_BITS_PER_WIDE_INT - 1))
*lv = signmask; : (*lv >> (prec - 1))) & 1);
}
else if ((prec - count) >= 2 * HOST_BITS_PER_WIDE_INT) 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 &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
*hv |= signmask << (prec - count - HOST_BITS_PER_WIDE_INT); *hv |= signmask << (prec - HOST_BITS_PER_WIDE_INT);
} }
else else
{ {
*hv = signmask; *hv = signmask;
*lv &= ~((unsigned HOST_WIDE_INT) (-1) << (prec - count)); *lv &= ~((unsigned HOST_WIDE_INT) (-1) << prec);
*lv |= signmask << (prec - count); *lv |= signmask << prec;
} }
} }
...@@ -895,7 +889,7 @@ double_int ...@@ -895,7 +889,7 @@ double_int
double_int_rshift (double_int a, HOST_WIDE_INT count, unsigned int prec, bool arith) double_int_rshift (double_int a, HOST_WIDE_INT count, unsigned int prec, bool arith)
{ {
double_int ret; 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; return ret;
} }
......
...@@ -300,9 +300,6 @@ extern int mul_double_with_sign (unsigned HOST_WIDE_INT, HOST_WIDE_INT, ...@@ -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, extern void lshift_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
HOST_WIDE_INT, unsigned int, HOST_WIDE_INT, unsigned int,
unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, bool); 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, 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,
HOST_WIDE_INT, unsigned HOST_WIDE_INT *, HOST_WIDE_INT, unsigned HOST_WIDE_INT *,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment