This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[wide-int] Various division fixes
- From: Richard Sandiford <rdsandiford at googlemail dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: zadeck at naturalbridge dot com, mikestump at comcast dot net, rguenther at suse dot de
- Date: Thu, 31 Oct 2013 09:01:21 +0000
- Subject: [wide-int] Various division fixes
- Authentication-results: sourceware.org; auth=none
There are several Ada failures on the branch, all related to division
and modulus:
- div_floor adjusted truncated negative quotients in the wrong direction
(up instead of down). E.g. -5 /[fl] 2 gave -1 rather than -3.
- {div,mod}_round used the wrong condition to check when rounding was needed.
- The routines checked for negative results by testing the sign of the
(truncated) quotient directly. That doesn't work when the true
quotient is in the range (-1, 0) and gets truncated to zero.
Tested on x86_64-linux-gnu and powerpc64-linux-gnu. OK to install?
Thanks,
Richard
Index: gcc/wide-int.h
===================================================================
--- gcc/wide-int.h 2013-10-31 08:46:18.081178550 +0000
+++ gcc/wide-int.h 2013-10-31 08:53:50.741900740 +0000
@@ -2250,8 +2250,8 @@ wi::div_floor (const T1 &x, const T2 &y,
yi.val, yi.len, yi.precision, sgn,
overflow));
remainder.set_len (remainder_len);
- if (wi::neg_p (quotient, sgn) && remainder != 0)
- return quotient + 1;
+ if (wi::neg_p (x, sgn) != wi::neg_p (y, sgn) && remainder != 0)
+ return quotient - 1;
return quotient;
}
@@ -2292,7 +2292,7 @@ wi::div_ceil (const T1 &x, const T2 &y,
yi.val, yi.len, yi.precision, sgn,
overflow));
remainder.set_len (remainder_len);
- if (!wi::neg_p (quotient, sgn) && remainder != 0)
+ if (wi::neg_p (x, sgn) == wi::neg_p (y, sgn) && remainder != 0)
return quotient + 1;
return quotient;
}
@@ -2322,10 +2322,10 @@ wi::div_round (const T1 &x, const T2 &y,
{
if (sgn == SIGNED)
{
- if (wi::gts_p (wi::lrshift (wi::abs (y), 1),
- wi::abs (remainder)))
+ if (wi::ges_p (wi::abs (remainder),
+ wi::lrshift (wi::abs (y), 1)))
{
- if (wi::neg_p (quotient))
+ if (wi::neg_p (x, sgn) != wi::neg_p (y, sgn))
return quotient - 1;
else
return quotient + 1;
@@ -2333,16 +2333,15 @@ wi::div_round (const T1 &x, const T2 &y,
}
else
{
- if (wi::gtu_p (wi::lrshift (y, 1), remainder))
+ if (wi::geu_p (remainder, wi::lrshift (y, 1)))
return quotient + 1;
}
}
return quotient;
}
-/* Return X / Y, rouding towards nearest with ties away from zero.
- Treat X and Y as having the signedness given by SGN. Store the
- remainder in *REMAINDER_PTR. */
+/* Return X / Y, rouding towards 0. Treat X and Y as having the
+ signedness given by SGN. Store the remainder in *REMAINDER_PTR. */
template <typename T1, typename T2>
inline WI_BINARY_RESULT (T1, T2)
wi::divmod_trunc (const T1 &x, const T2 &y, signop sgn,
@@ -2425,7 +2424,7 @@ wi::mod_floor (const T1 &x, const T2 &y,
overflow));
remainder.set_len (remainder_len);
- if (wi::neg_p (quotient, sgn) && remainder != 0)
+ if (wi::neg_p (x, sgn) != wi::neg_p (y, sgn) && remainder != 0)
return remainder + y;
return remainder;
}
@@ -2461,7 +2460,7 @@ wi::mod_ceil (const T1 &x, const T2 &y,
overflow));
remainder.set_len (remainder_len);
- if (!wi::neg_p (quotient, sgn) && remainder != 0)
+ if (wi::neg_p (x, sgn) == wi::neg_p (y, sgn) && remainder != 0)
return remainder - y;
return remainder;
}
@@ -2491,10 +2490,10 @@ wi::mod_round (const T1 &x, const T2 &y,
{
if (sgn == SIGNED)
{
- if (wi::gts_p (wi::lrshift (wi::abs (y), 1),
- wi::abs (remainder)))
+ if (wi::ges_p (wi::abs (remainder),
+ wi::lrshift (wi::abs (y), 1)))
{
- if (wi::neg_p (quotient))
+ if (wi::neg_p (x, sgn) != wi::neg_p (y, sgn))
return remainder + y;
else
return remainder - y;
@@ -2502,7 +2501,7 @@ wi::mod_round (const T1 &x, const T2 &y,
}
else
{
- if (wi::gtu_p (wi::lrshift (y, 1), remainder))
+ if (wi::geu_p (remainder, wi::lrshift (y, 1)))
return remainder - y;
}
}