On December 31, 2020 10:31:00 AM GMT+01:00, Jakub Jelinek <ja...@redhat.com> wrote: >Hi! > >The following testcase is miscompiled, because niter analysis >miscomputes >the number of iterations to 0. >The problem is that niter analysis uses mpz_t (wonder why, wouldn't >widest_int do the same job?)
The mpz use predates wide int and double int wasn't enough. and when wi::to_mpz is called e.g. on the >TYPE_MAX_VALUE of __uint128_t, it initializes the mpz_t result with >wrong >value. >wi::to_mpz has code to handle negative wide_ints in signed types by >inverting all bits, importing to mpz and complementing it, which is >fine, >but doesn't handle correctly the case when the wide_int's len (times >HOST_BITS_PER_WIDE_INT) is smaller than precision when wi::neg_p. >E.g. the 0xffffffffffffffffffffffffffffffff TYPE_MAX_VALUE is >represented >in wide_int as 0xffffffffffffffff len 1, and wi::to_mpz would create >0xffffffffffffffff mpz_t value from that. >This patch handles it by adding the needed -1 host wide int words (and >has >also code to deal with precision that aren't multiple of >HOST_BITS_PER_WIDE_INT). > >Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? Ok. Richard. >2020-12-31 Jakub Jelinek <ja...@redhat.com> > > PR tree-optimization/98474 > * wide-int.cc (wi::to_mpz): If wide_int has MSB set, but type > is unsigned and excess negative, append set bits after len until > precision. > > * gcc.c-torture/execute/pr98474.c: New test. > >--- gcc/wide-int.cc.jj 2020-12-30 10:31:33.402981204 +0100 >+++ gcc/wide-int.cc 2020-12-30 10:44:57.628947066 +0100 >@@ -230,6 +230,20 @@ wi::to_mpz (const wide_int_ref &x, mpz_t > 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); > } >--- gcc/testsuite/gcc.c-torture/execute/pr98474.c.jj 2020-12-30 >10:53:31.847166586 +0100 >+++ gcc/testsuite/gcc.c-torture/execute/pr98474.c 2020-12-30 >10:55:52.542584936 +0100 >@@ -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; >+} > > Jakub