mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-26 00:51:04 +08:00
PR 69400: Invalid 128-bit modulus result
As described in the PR, wi::divmod_internal was sign- rather than zero-extending a modulus result in cases where the result has fewer HWIs than the precision and the upper bit of the upper HWI was set. This patch tries to make things more robust by getting wi_pack to handle the canonicalisation step itself. Tested on x86_64-linux-gnu. I added tests to the wide-int plugin since that seemed more direct. gcc/ PR tree-optimization/69400 * wide-int.cc (wi_pack): Take the precision as argument and perform canonicalization here rather than in the callers. Use the main loop to handle all full-width HWIs. Add a zero HWI if in_len isn't a full result. (wi::divmod_internal): Update accordingly. (wi::mul_internal): Likewise. Simplify. gcc/testsuite/ PR tree-optimization/69400 * gcc.dg/plugin/wide-int_plugin.c (test_wide_int_mod_trunc): New function. (plugin_init): Call it. * gcc.dg/torture/pr69400.c: New test. From-SVN: r232817
This commit is contained in:
parent
7ddfb31dfd
commit
5ee31e57d2
@ -1,3 +1,13 @@
|
|||||||
|
2016-01-26 Richard Sandiford <richard.sandiford@arm.com>
|
||||||
|
|
||||||
|
PR tree-optimization/69400
|
||||||
|
* wide-int.cc (wi_pack): Take the precision as argument and
|
||||||
|
perform canonicalization here rather than in the callers.
|
||||||
|
Use the main loop to handle all full-width HWIs. Add a
|
||||||
|
zero HWI if in_len isn't a full result.
|
||||||
|
(wi::divmod_internal): Update accordingly.
|
||||||
|
(wi::mul_internal): Likewise. Simplify.
|
||||||
|
|
||||||
2016-01-25 Aditya Kumar <aditya.k7@samsung.com>
|
2016-01-25 Aditya Kumar <aditya.k7@samsung.com>
|
||||||
Sebastian Pop <s.pop@samsung.com>
|
Sebastian Pop <s.pop@samsung.com>
|
||||||
|
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
2016-01-26 Richard Sandiford <richard.sandiford@arm.com>
|
||||||
|
|
||||||
|
PR tree-optimization/69400
|
||||||
|
* gcc.dg/plugin/wide-int_plugin.c (test_wide_int_mod_trunc): New
|
||||||
|
function.
|
||||||
|
(plugin_init): Call it.
|
||||||
|
* gcc.dg/torture/pr69400.c: New test.
|
||||||
|
|
||||||
2016-01-26 Christophe Lyon <christophe.lyon@linaro.org>
|
2016-01-26 Christophe Lyon <christophe.lyon@linaro.org>
|
||||||
|
|
||||||
* gcc.target/arm/pr68674.c: Check and use arm_fp effective target.
|
* gcc.target/arm/pr68674.c: Check and use arm_fp effective target.
|
||||||
|
@ -36,11 +36,44 @@ test_wide_int_round_sdiv (void)
|
|||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_wide_int_mod_trunc (void)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 1; i < MAX_BITSIZE_MODE_ANY_INT; ++i)
|
||||||
|
{
|
||||||
|
if (wi::smod_trunc (wi::lshift (1, i + 1) - 3,
|
||||||
|
wi::lshift (1, i) - 1)
|
||||||
|
!= wi::lshift (1, i) - 2)
|
||||||
|
abort ();
|
||||||
|
for (unsigned int base = 32; base <= MAX_BITSIZE_MODE_ANY_INT; base *= 2)
|
||||||
|
for (int bias = -1; bias <= 1; ++bias)
|
||||||
|
{
|
||||||
|
unsigned int precision = base + bias;
|
||||||
|
if (i + 1 < precision && precision <= MAX_BITSIZE_MODE_ANY_INT)
|
||||||
|
{
|
||||||
|
wide_int one = wi::uhwi (1, precision);
|
||||||
|
wide_int a = wi::lshift (one, i + 1) - 3;
|
||||||
|
wide_int b = wi::lshift (one, i) - 1;
|
||||||
|
wide_int c = wi::lshift (one, i) - 2;
|
||||||
|
if (wi::umod_trunc (a, b) != c)
|
||||||
|
abort ();
|
||||||
|
if (wi::smod_trunc (a, b) != c)
|
||||||
|
abort ();
|
||||||
|
if (wi::smod_trunc (-a, b) != -c)
|
||||||
|
abort ();
|
||||||
|
if (wi::smod_trunc (a, -b) != c)
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
plugin_init (struct plugin_name_args *plugin_info,
|
plugin_init (struct plugin_name_args *plugin_info,
|
||||||
struct plugin_gcc_version *version)
|
struct plugin_gcc_version *version)
|
||||||
{
|
{
|
||||||
test_double_int_round_udiv ();
|
test_double_int_round_udiv ();
|
||||||
test_wide_int_round_sdiv ();
|
test_wide_int_round_sdiv ();
|
||||||
|
test_wide_int_mod_trunc ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
20
gcc/testsuite/gcc.dg/torture/pr69400.c
Normal file
20
gcc/testsuite/gcc.dg/torture/pr69400.c
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/* { dg-do run { target int128 } } */
|
||||||
|
|
||||||
|
typedef unsigned __int128 u128;
|
||||||
|
|
||||||
|
u128 __attribute__((noinline, noclone))
|
||||||
|
foo(void)
|
||||||
|
{
|
||||||
|
u128 u = -2;
|
||||||
|
u %= 0xffffffffffffffffllu;
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
u128 x = foo();
|
||||||
|
if (x != 0xfffffffffffffffellu)
|
||||||
|
__builtin_abort();
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1214,30 +1214,32 @@ wi_unpack (unsigned HOST_HALF_WIDE_INT *result, const HOST_WIDE_INT *input,
|
|||||||
result[j++] = mask;
|
result[j++] = mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The inverse of wi_unpack. IN_LEN is the the number of input
|
/* The inverse of wi_unpack. IN_LEN is the number of input
|
||||||
blocks. The number of output blocks will be half this amount. */
|
blocks and PRECISION is the precision of the result. Return the
|
||||||
static void
|
number of blocks in the canonicalized result. */
|
||||||
wi_pack (unsigned HOST_WIDE_INT *result,
|
static unsigned int
|
||||||
|
wi_pack (HOST_WIDE_INT *result,
|
||||||
const unsigned HOST_HALF_WIDE_INT *input,
|
const unsigned HOST_HALF_WIDE_INT *input,
|
||||||
unsigned int in_len)
|
unsigned int in_len, unsigned int precision)
|
||||||
{
|
{
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
unsigned int j = 0;
|
unsigned int j = 0;
|
||||||
|
unsigned int blocks_needed = BLOCKS_NEEDED (precision);
|
||||||
|
|
||||||
while (i + 2 < in_len)
|
while (i + 1 < in_len)
|
||||||
{
|
{
|
||||||
result[j++] = (unsigned HOST_WIDE_INT)input[i]
|
result[j++] = ((unsigned HOST_WIDE_INT) input[i]
|
||||||
| ((unsigned HOST_WIDE_INT)input[i + 1]
|
| ((unsigned HOST_WIDE_INT) input[i + 1]
|
||||||
<< HOST_BITS_PER_HALF_WIDE_INT);
|
<< HOST_BITS_PER_HALF_WIDE_INT));
|
||||||
i += 2;
|
i += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle the case where in_len is odd. For this we zero extend. */
|
/* Handle the case where in_len is odd. For this we zero extend. */
|
||||||
if (in_len & 1)
|
if (in_len & 1)
|
||||||
result[j++] = (unsigned HOST_WIDE_INT)input[i];
|
result[j++] = (unsigned HOST_WIDE_INT) input[i];
|
||||||
else
|
else if (j < blocks_needed)
|
||||||
result[j++] = (unsigned HOST_WIDE_INT)input[i]
|
result[j++] = 0;
|
||||||
| ((unsigned HOST_WIDE_INT)input[i + 1] << HOST_BITS_PER_HALF_WIDE_INT);
|
return canonize (result, j, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Multiply Op1 by Op2. If HIGH is set, only the upper half of the
|
/* Multiply Op1 by Op2. If HIGH is set, only the upper half of the
|
||||||
@ -1460,19 +1462,8 @@ wi::mul_internal (HOST_WIDE_INT *val, const HOST_WIDE_INT *op1val,
|
|||||||
*overflow = true;
|
*overflow = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (high)
|
int r_offset = high ? half_blocks_needed : 0;
|
||||||
{
|
return wi_pack (val, &r[r_offset], half_blocks_needed, prec);
|
||||||
/* compute [prec] <- ([prec] * [prec]) >> [prec] */
|
|
||||||
wi_pack ((unsigned HOST_WIDE_INT *) val,
|
|
||||||
&r[half_blocks_needed], half_blocks_needed);
|
|
||||||
return canonize (val, blocks_needed, prec);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* compute [prec] <- ([prec] * [prec]) && ((1 << [prec]) - 1) */
|
|
||||||
wi_pack ((unsigned HOST_WIDE_INT *) val, r, half_blocks_needed);
|
|
||||||
return canonize (val, blocks_needed, prec);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the population count of X. */
|
/* Compute the population count of X. */
|
||||||
@ -1847,8 +1838,7 @@ wi::divmod_internal (HOST_WIDE_INT *quotient, unsigned int *remainder_len,
|
|||||||
unsigned int quotient_len = 0;
|
unsigned int quotient_len = 0;
|
||||||
if (quotient)
|
if (quotient)
|
||||||
{
|
{
|
||||||
wi_pack ((unsigned HOST_WIDE_INT *) quotient, b_quotient, m);
|
quotient_len = wi_pack (quotient, b_quotient, m, dividend_prec);
|
||||||
quotient_len = canonize (quotient, (m + 1) / 2, dividend_prec);
|
|
||||||
/* The quotient is neg if exactly one of the divisor or dividend is
|
/* The quotient is neg if exactly one of the divisor or dividend is
|
||||||
neg. */
|
neg. */
|
||||||
if (dividend_neg != divisor_neg)
|
if (dividend_neg != divisor_neg)
|
||||||
@ -1859,8 +1849,7 @@ wi::divmod_internal (HOST_WIDE_INT *quotient, unsigned int *remainder_len,
|
|||||||
|
|
||||||
if (remainder)
|
if (remainder)
|
||||||
{
|
{
|
||||||
wi_pack ((unsigned HOST_WIDE_INT *) remainder, b_remainder, n);
|
*remainder_len = wi_pack (remainder, b_remainder, n, dividend_prec);
|
||||||
*remainder_len = canonize (remainder, (n + 1) / 2, dividend_prec);
|
|
||||||
/* The remainder is always the same sign as the dividend. */
|
/* The remainder is always the same sign as the dividend. */
|
||||||
if (dividend_neg)
|
if (dividend_neg)
|
||||||
*remainder_len = wi::sub_large (remainder, zeros, 1, remainder,
|
*remainder_len = wi::sub_large (remainder, zeros, 1, remainder,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user