This is an old bug in div_and_round_double for ROUND_DIV_EXPR: when the code
detects that it needs to adjust the quotient, it needs to decide whether it
increases or decreases it by 1. This only depends on the expected sign of the
quotient, but the test reads:
if (*hquo < 0)
So if the quotient is 0, the code will always bump it, thus yielding 1, even
if the expected quotient is negative. This causes the attached Ada testcase
to fail at -O on all active branches... except for mainline, because of the
correct implementation of the same test in wi::div_round:
if (wi::neg_p (x, sgn) != wi::neg_p (y, sgn))
return quotient - 1;
else
return quotient + 1;
It turns out that div_and_round_double has a predicate quo_neg that implements
the same test as the wide-int one and ought to be used here.
Tested on x86_64-suse-linux (of course this probably doesn't mean anything on
the mainline, but it was also test with 4.7 and 4.9 compilers) and applied on
the mainline as obvious.
2014-05-27 Eric Botcazou <ebotca...@adacore.com>
* double-int.c (div_and_round_double) <ROUND_DIV_EXPR>: Use the proper
predicate to detect a negative quotient.
2014-05-27 Eric Botcazou <ebotca...@adacore.com>
* gnat.dg/overflow_fixed.adb: New test.
--
Eric Botcazou
Index: double-int.c
===================================================================
--- double-int.c (revision 210911)
+++ double-int.c (working copy)
@@ -588,7 +588,7 @@ div_and_round_double (unsigned code, int
== (unsigned HOST_WIDE_INT) htwice)
&& (labs_den <= ltwice)))
{
- if (*hquo < 0)
+ if (quo_neg)
/* quo = quo - 1; */
add_double (*lquo, *hquo,
(HOST_WIDE_INT) -1, (HOST_WIDE_INT) -1, lquo, hquo);
-- { dg-do run }
-- { dg-options "-gnato -O" }
procedure Overflow_Fixed is
type Unsigned_8_Bit is mod 2**8;
procedure Fixed_To_Eight (Value : Duration) is
Item : Unsigned_8_Bit;
begin
Item := Unsigned_8_Bit(Value);
raise Program_Error;
exception
when Constraint_Error => null; -- expected case
end;
begin
Fixed_To_Eight (-0.5);
end;