> Am 04.06.2025 um 23:04 schrieb Jakub Jelinek <ja...@redhat.com>:
> 
> Hi!
> 
> The function has 2 problems, one is _BitInt specific and the other is
> most likely also reproduceable only with it.
> 
> The first issue is that I've missed updating the function for _BitInt,
> maxbitlen as MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT
> obviously isn't guaranteed to be larger than any integral type we might
> want to convert at compile time from wide_int to REAL_VALUE_FORMAT.
> Just using len instead of it works fine, at least when used after
> HOST_BITS_PER_WIDE_INT is added to it and it is truncated to multiples
> of HOST_BITS_PER_WIDE_INT.
> 
> The other bug is that if the value has too many significant bits (formerly
> maxbitlen - cnt_l_z, now len - cnt_l_z), the code just shifts it right and
> adds the shift count to the future exponent.  That isn't correct for
> rounding as the testcase attempts to show, the internal real format has more
> bits than any precision in supported format, but we still need to
> distinguish bewtween values exactly half way between representable floating
> point values (those should be rounded to even) and the case when we've
> shifted away some non-zero bits, so the value was tiny bit larger than half
> way and then we should round up.
> 
> The patch uses something like e.g. soft-fp uses in these cases, right shift
> with sticky bit in the least significant bit.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/15/14?

Ok

Thanks,
Richard 

> 2025-06-04  Jakub Jelinek  <ja...@redhat.com>
> 
>    PR middle-end/120547
>    * real.cc (real_from_integer): Remove maxbitlen variable, use
>    len instead of that.  When shifting right, or in 1 if any of the
>    shifted away bits are non-zero.  Formatting fix.
> 
>    * gcc.dg/bitint-123.c: New test.
> 
> --- gcc/real.cc.jj    2025-04-08 14:08:59.847162199 +0200
> +++ gcc/real.cc    2025-06-04 18:17:04.018080378 +0200
> @@ -2230,7 +2230,6 @@ real_from_integer (REAL_VALUE_TYPE *r, f
>     {
>       unsigned int len = val_in.get_precision ();
>       int i, j, e = 0;
> -      int maxbitlen = MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT;
>       const unsigned int realmax = (SIGNIFICAND_BITS / HOST_BITS_PER_WIDE_INT
>                    * HOST_BITS_PER_WIDE_INT);
> 
> @@ -2238,12 +2237,6 @@ real_from_integer (REAL_VALUE_TYPE *r, f
>       r->cl = rvc_normal;
>       r->sign = wi::neg_p (val_in, sgn);
> 
> -      /* We have to ensure we can negate the largest negative number.  */
> -      wide_int val = wide_int::from (val_in, maxbitlen, sgn);
> -
> -      if (r->sign)
> -    val = -val;
> -
>       /* Ensure a multiple of HOST_BITS_PER_WIDE_INT, ceiling, as elt
>     won't work with precisions that are not a multiple of
>     HOST_BITS_PER_WIDE_INT.  */
> @@ -2252,7 +2245,13 @@ real_from_integer (REAL_VALUE_TYPE *r, f
>       /* Ensure we can represent the largest negative number.  */
>       len += 1;
> 
> -      len = len/HOST_BITS_PER_WIDE_INT * HOST_BITS_PER_WIDE_INT;
> +      len = len / HOST_BITS_PER_WIDE_INT * HOST_BITS_PER_WIDE_INT;
> +
> +      /* We have to ensure we can negate the largest negative number.  */
> +      wide_int val = wide_int::from (val_in, len, sgn);
> +
> +      if (r->sign)
> +    val = -val;
> 
>       /* Cap the size to the size allowed by real.h.  */
>       if (len > realmax)
> @@ -2260,14 +2259,18 @@ real_from_integer (REAL_VALUE_TYPE *r, f
>      HOST_WIDE_INT cnt_l_z;
>      cnt_l_z = wi::clz (val);
> 
> -      if (maxbitlen - cnt_l_z > realmax)
> +      if (len - cnt_l_z > realmax)
>        {
> -          e = maxbitlen - cnt_l_z - realmax;
> +          e = len - cnt_l_z - realmax;
> 
>          /* This value is too large, we must shift it right to
>         preserve all the bits we can, and then bump the
> -         exponent up by that amount.  */
> -          val = wi::lrshift (val, e);
> +         exponent up by that amount, but or in 1 if any of
> +         the shifted out bits are non-zero.  */
> +          if (wide_int::from (val, e, UNSIGNED) != 0)
> +        val = wi::set_bit (wi::lrshift (val, e), 0);
> +          else
> +        val = wi::lrshift (val, e);
>        }
>      len = realmax;
>    }
> --- gcc/testsuite/gcc.dg/bitint-123.c.jj    2025-06-04 18:29:29.487456324 
> +0200
> +++ gcc/testsuite/gcc.dg/bitint-123.c    2025-06-04 18:31:13.941077762 +0200
> @@ -0,0 +1,26 @@
> +/* PR middle-end/120547 */
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-O2" } */
> +/* { dg-add-options float64 } */
> +/* { dg-require-effective-target float64 } */
> +
> +#define CHECK(x, y) \
> +  if ((_Float64) x != (_Float64) y                \
> +      || (_Float64) (x + 1) != (_Float64) (y + 1))        \
> +    __builtin_abort ()
> +
> +int
> +main ()
> +{
> +  unsigned long long a = 0x20000000000001ULL << 7;
> +  volatile unsigned long long b = a;
> +  CHECK (a, b);
> +#if __BITINT_MAXWIDTH__ >= 4096
> +  unsigned _BitInt(4096) c = ((unsigned _BitInt(4096)) 0x20000000000001ULL) 
> << 253;
> +  volatile unsigned _BitInt(4096) d = c;
> +  CHECK (c, d);
> +  unsigned _BitInt(4096) e = ((unsigned _BitInt(4096)) 0x20000000000001ULL) 
> << 931;
> +  volatile unsigned _BitInt(4096) f = e;
> +  CHECK (e, f);
> +#endif
> +}
> 
>    Jakub
> 

Reply via email to