For signed min / -1 we set the overflow flag (good) but also returned a
quotient of 0. It should be 0x80...0 instead. Since that's also the
value of the original dividend, we can just copy the representation over.
The value for division by 0 is probably pretty arbitrary. double-int.c
seems to treat it as division by one:
if (hden == 0 && lden == 0)
overflow = 1, lden = 1;
and while not important, it has the nice feature that here too we could
just copy the original dividend, rather than treat it differently from
signed min / -1.
This fixes libjava's Divide_1, which was the last remaining regression
on x86_64-linux-gnu. I have a couple of other patches queued up, but
I'm still running tests to compare the asm output for the gcc and g++
testsuites on a range of targets. (FWIW, the first round of these
tests picked up the same bug as Divide_1, in the output for
gcc.c-torture/compile/20010404-1.c.)
OK to install?
Thanks,
Richard
Index: gcc/wide-int.cc
===================================================================
--- gcc/wide-int.cc 2014-04-24 09:51:08.056774754 +0100
+++ gcc/wide-int.cc 2014-04-24 11:52:35.996541888 +0100
@@ -1726,8 +1726,10 @@ wi::divmod_internal (HOST_WIDE_INT *quot
&& wi::only_sign_bit_p (dividend))
overflow = true;
- /* If overflow is set, just get out. There will only be grief by
- continuing. */
+ /* Handle the overflow cases. Viewed as unsigned value, the quotient of
+ (signed min / -1) has the same representation as the orignal dividend.
+ We have traditionally made division by zero act as division by one,
+ so there too we use the original dividend. */
if (overflow)
{
if (remainder)
@@ -1738,8 +1741,9 @@ wi::divmod_internal (HOST_WIDE_INT *quot
if (oflow != 0)
*oflow = true;
if (quotient)
- quotient[0] = 0;
- return 1;
+ for (unsigned int i = 0; i < dividend_len; ++i)
+ quotient[i] = dividend_val[i];
+ return dividend_len;
}
if (oflow)