diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/pr98474.c | 30 | ||||
-rw-r--r-- | gcc/wide-int.cc | 14 |
2 files changed, 44 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr98474.c b/gcc/testsuite/gcc.c-torture/execute/pr98474.c new file mode 100644 index 0000000..8c28799 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr98474.c @@ -0,0 +1,30 @@ +/* PR tree-optimization/98474 */ + +#ifdef __SIZEOF_INT128__ +typedef __uint128_t T; +#define N (__SIZEOF_INT128__ * __CHAR_BIT__ / 2) +#else +typedef unsigned long long T; +#define N (__SIZEOF_LONG_LONG__ * __CHAR_BIT__ / 2) +#endif + +__attribute__ ((noipa)) void +foo (T *x) +{ + *x += ((T) 1) << (N + 1); +} + +int +main () +{ + T a = ((T) 1) << (N + 1); + T b = a; + T n; + foo (&b); + n = b; + while (n >= a) + n -= a; + if ((int) (n >> N) != 0) + __builtin_abort (); + return 0; +} diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc index 99d7ded..447bac1 100644 --- a/gcc/wide-int.cc +++ b/gcc/wide-int.cc @@ -230,6 +230,20 @@ wi::to_mpz (const wide_int_ref &x, mpz_t result, signop sgn) t[len - 1] = (unsigned HOST_WIDE_INT) v[len - 1] << excess >> excess; mpz_import (result, len, -1, sizeof (HOST_WIDE_INT), 0, 0, t); } + else if (excess < 0 && wi::neg_p (x)) + { + int extra + = (-excess + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT; + HOST_WIDE_INT *t = XALLOCAVEC (HOST_WIDE_INT, len + extra); + for (int i = 0; i < len; i++) + t[i] = v[i]; + for (int i = 0; i < extra; i++) + t[len + i] = -1; + excess = (-excess) % HOST_BITS_PER_WIDE_INT; + if (excess) + t[len + extra - 1] = (HOST_WIDE_INT_1U << excess) - 1; + mpz_import (result, len + extra, -1, sizeof (HOST_WIDE_INT), 0, 0, t); + } else mpz_import (result, len, -1, sizeof (HOST_WIDE_INT), 0, 0, v); } |