re PR middle-end/64182 (wide-int rounding division is broken)
gcc/ PR middle-end/64182 * wide-int.h (wi::div_round, wi::mod_round): Fix rounding of tied cases. * double-int.c (div_and_round_double): Fix handling of unsigned cases. Use same rounding approach as wide-int.h. gcc/testsuite/ 2014-xx-xx Richard Sandiford <richard.sandiford@arm.com> Joseph Myers <joseph@codesourcery.com> PR middle-end/64182 * gcc.dg/plugin/wide-int-test-1.c, gcc.dg/plugin/wide-int_plugin.c: New test. * gcc.dg/plugin/plugin.exp: Register it. * gnat.dg/round_div.adb: New test. Co-Authored-By: Joseph Myers <joseph@codesourcery.com> From-SVN: r218678
This commit is contained in:
parent
8f596ff51a
commit
4db4954fc5
8 changed files with 107 additions and 18 deletions
|
@ -1,3 +1,11 @@
|
|||
2014-12-12 Richard Sandiford <richard.sandiford@arm.com>
|
||||
|
||||
PR middle-end/64182
|
||||
* wide-int.h (wi::div_round, wi::mod_round): Fix rounding of tied
|
||||
cases.
|
||||
* double-int.c (div_and_round_double): Fix handling of unsigned
|
||||
cases. Use same rounding approach as wide-int.h.
|
||||
|
||||
2014-12-12 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR middle-end/64274
|
||||
|
|
|
@ -569,24 +569,23 @@ div_and_round_double (unsigned code, int uns,
|
|||
{
|
||||
unsigned HOST_WIDE_INT labs_rem = *lrem;
|
||||
HOST_WIDE_INT habs_rem = *hrem;
|
||||
unsigned HOST_WIDE_INT labs_den = lden, ltwice;
|
||||
HOST_WIDE_INT habs_den = hden, htwice;
|
||||
unsigned HOST_WIDE_INT labs_den = lden, lnegabs_rem, ldiff;
|
||||
HOST_WIDE_INT habs_den = hden, hnegabs_rem, hdiff;
|
||||
|
||||
/* Get absolute values. */
|
||||
if (*hrem < 0)
|
||||
if (!uns && *hrem < 0)
|
||||
neg_double (*lrem, *hrem, &labs_rem, &habs_rem);
|
||||
if (hden < 0)
|
||||
if (!uns && hden < 0)
|
||||
neg_double (lden, hden, &labs_den, &habs_den);
|
||||
|
||||
/* If (2 * abs (lrem) >= abs (lden)), adjust the quotient. */
|
||||
mul_double ((HOST_WIDE_INT) 2, (HOST_WIDE_INT) 0,
|
||||
labs_rem, habs_rem, <wice, &htwice);
|
||||
/* If abs(rem) >= abs(den) - abs(rem), adjust the quotient. */
|
||||
neg_double (labs_rem, habs_rem, &lnegabs_rem, &hnegabs_rem);
|
||||
add_double (labs_den, habs_den, lnegabs_rem, hnegabs_rem,
|
||||
&ldiff, &hdiff);
|
||||
|
||||
if (((unsigned HOST_WIDE_INT) habs_den
|
||||
< (unsigned HOST_WIDE_INT) htwice)
|
||||
|| (((unsigned HOST_WIDE_INT) habs_den
|
||||
== (unsigned HOST_WIDE_INT) htwice)
|
||||
&& (labs_den <= ltwice)))
|
||||
if (((unsigned HOST_WIDE_INT) habs_rem
|
||||
> (unsigned HOST_WIDE_INT) hdiff)
|
||||
|| (habs_rem == hdiff && labs_rem >= ldiff))
|
||||
{
|
||||
if (quo_neg)
|
||||
/* quo = quo - 1; */
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
2014-12-12 Richard Sandiford <richard.sandiford@arm.com>
|
||||
Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
PR middle-end/64182
|
||||
* gcc.dg/plugin/wide-int-test-1.c,
|
||||
gcc.dg/plugin/wide-int_plugin.c: New test.
|
||||
* gcc.dg/plugin/plugin.exp: Register it.
|
||||
* gnat.dg/round_div.adb: New test.
|
||||
|
||||
2014-12-12 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR tree-optimization/64269
|
||||
|
|
|
@ -62,6 +62,7 @@ set plugin_test_list [list \
|
|||
{ sreal_plugin.c sreal-test-1.c } \
|
||||
{ start_unit_plugin.c start_unit-test-1.c } \
|
||||
{ finish_unit_plugin.c finish_unit-test-1.c } \
|
||||
{ wide-int_plugin.c wide-int-test-1.c } \
|
||||
]
|
||||
|
||||
foreach plugin_test $plugin_test_list {
|
||||
|
|
9
gcc/testsuite/gcc.dg/plugin/wide-int-test-1.c
Normal file
9
gcc/testsuite/gcc.dg/plugin/wide-int-test-1.c
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* Test that pass is inserted and invoked once. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O" } */
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
46
gcc/testsuite/gcc.dg/plugin/wide-int_plugin.c
Normal file
46
gcc/testsuite/gcc.dg/plugin/wide-int_plugin.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include "config.h"
|
||||
#include "gcc-plugin.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
||||
int plugin_is_GPL_compatible;
|
||||
|
||||
static void
|
||||
test_double_int_round_udiv (void)
|
||||
{
|
||||
double_int dmin = { 0, HOST_WIDE_INT_MIN };
|
||||
double_int dmax = { -1, HOST_WIDE_INT_MAX };
|
||||
double_int dnegone = { -1, -1 };
|
||||
double_int mod, div;
|
||||
div = dmin.udivmod (dnegone, ROUND_DIV_EXPR, &mod);
|
||||
if (div.low != 1 || div.high != 0
|
||||
|| mod.low != 1 || mod.high != HOST_WIDE_INT_MIN)
|
||||
abort ();
|
||||
div = dmax.udivmod (dnegone, ROUND_DIV_EXPR, &mod);
|
||||
if (div.low != 0 || div.high != 0
|
||||
|| mod.low != dmax.low || mod.high != dmax.high)
|
||||
abort ();
|
||||
}
|
||||
|
||||
static void
|
||||
test_wide_int_round_sdiv (void)
|
||||
{
|
||||
if (wi::ne_p (wi::div_round (2, 3, SIGNED), 1))
|
||||
abort ();
|
||||
if (wi::ne_p (wi::div_round (1, 3, SIGNED), 0))
|
||||
abort ();
|
||||
if (wi::ne_p (wi::mod_round (2, 3, SIGNED), -1))
|
||||
abort ();
|
||||
if (wi::ne_p (wi::mod_round (1, 3, SIGNED), 1))
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
plugin_init (struct plugin_name_args *plugin_info,
|
||||
struct plugin_gcc_version *version)
|
||||
{
|
||||
test_double_int_round_udiv ();
|
||||
test_wide_int_round_sdiv ();
|
||||
return 0;
|
||||
}
|
17
gcc/testsuite/gnat.dg/round_div.adb
Normal file
17
gcc/testsuite/gnat.dg/round_div.adb
Normal file
|
@ -0,0 +1,17 @@
|
|||
-- { dg-do run }
|
||||
-- { dg-options "-O3" }
|
||||
procedure Round_Div is
|
||||
type Fixed is delta 1.0 range -2147483648.0 .. 2147483647.0;
|
||||
A : Fixed := 1.0;
|
||||
B : Fixed := 3.0;
|
||||
C : Integer;
|
||||
function Divide (X, Y : Fixed) return Integer is
|
||||
begin
|
||||
return Integer (X / Y);
|
||||
end;
|
||||
begin
|
||||
C := Divide (A, B);
|
||||
if C /= 0 then
|
||||
raise Program_Error;
|
||||
end if;
|
||||
end Round_Div;
|
|
@ -2616,8 +2616,8 @@ wi::div_round (const T1 &x, const T2 &y, signop sgn, bool *overflow)
|
|||
{
|
||||
if (sgn == SIGNED)
|
||||
{
|
||||
if (wi::ges_p (wi::abs (remainder),
|
||||
wi::lrshift (wi::abs (y), 1)))
|
||||
WI_BINARY_RESULT (T1, T2) abs_remainder = wi::abs (remainder);
|
||||
if (wi::geu_p (abs_remainder, wi::sub (wi::abs (y), abs_remainder)))
|
||||
{
|
||||
if (wi::neg_p (x, sgn) != wi::neg_p (y, sgn))
|
||||
return quotient - 1;
|
||||
|
@ -2627,7 +2627,7 @@ wi::div_round (const T1 &x, const T2 &y, signop sgn, bool *overflow)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (wi::geu_p (remainder, wi::lrshift (y, 1)))
|
||||
if (wi::geu_p (remainder, wi::sub (y, remainder)))
|
||||
return quotient + 1;
|
||||
}
|
||||
}
|
||||
|
@ -2784,8 +2784,8 @@ wi::mod_round (const T1 &x, const T2 &y, signop sgn, bool *overflow)
|
|||
{
|
||||
if (sgn == SIGNED)
|
||||
{
|
||||
if (wi::ges_p (wi::abs (remainder),
|
||||
wi::lrshift (wi::abs (y), 1)))
|
||||
WI_BINARY_RESULT (T1, T2) abs_remainder = wi::abs (remainder);
|
||||
if (wi::geu_p (abs_remainder, wi::sub (wi::abs (y), abs_remainder)))
|
||||
{
|
||||
if (wi::neg_p (x, sgn) != wi::neg_p (y, sgn))
|
||||
return remainder + y;
|
||||
|
@ -2795,7 +2795,7 @@ wi::mod_round (const T1 &x, const T2 &y, signop sgn, bool *overflow)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (wi::geu_p (remainder, wi::lrshift (y, 1)))
|
||||
if (wi::geu_p (remainder, wi::sub (y, remainder)))
|
||||
return remainder - y;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue