> 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
>