> Am 17.06.2025 um 23:04 schrieb Jakub Jelinek <ja...@redhat.com>:
> 
> Hi!
> 
> The following testcase shows that while at runtime we handle conversions
> between _Decimal{64,128} and large _BitInt correctly, at compile time we
> mishandle them in both directions, in one direction we end up in ICE in
> decimal_from_integer callee because the char buffer is too short for the
> needed number of decimal digits, in the conversion of dfp to large _BitInt
> we return 0 in the wide_int.
> 
> The following patch fixes the ICE by using larger buffer (XALLOCAVEC
> allocated, it will be never larger than 65536 / 3 bytes) in the larger
> _BitInt case, and the other direction by setting exponent to exp % 19
> and instead multiplying the result by needed powers of 10^19 (10^19 chosen
> as largest power of ten that can fit into UHWI).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for
> trunk/15.2/14.4?

Ok

Richard 

> 2025-06-17  Jakub Jelinek  <ja...@redhat.com>
> 
>    PR middle-end/120631
>    * real.cc (decimal_from_integer): Add digits argument, if larger than
>    256, use XALLOCAVEC allocated buffer.
>    (real_from_integer): Pass val_in's precision divided by 3 to
>    decimal_from_integer.
>    * dfp.cc (decimal_real_to_integer): For precision > 128 if finite
>    and exponent is large, decrease exponent and multiply resulting
>    wide_int by powers of 10^19.
> 
>    * gcc.dg/dfp/bitint-9.c: New test.
> 
> --- gcc/real.cc.jj    2025-06-05 15:47:08.313244971 +0200
> +++ gcc/real.cc    2025-06-17 14:40:16.565601561 +0200
> @@ -101,7 +101,7 @@ static int do_compare (const REAL_VALUE_
> static void do_fix_trunc (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
> 
> static unsigned long rtd_divmod (REAL_VALUE_TYPE *, REAL_VALUE_TYPE *);
> -static void decimal_from_integer (REAL_VALUE_TYPE *);
> +static void decimal_from_integer (REAL_VALUE_TYPE *, int);
> static void decimal_integer_string (char *, const REAL_VALUE_TYPE *,
>                    size_t);
> 
> @@ -2309,7 +2309,9 @@ real_from_integer (REAL_VALUE_TYPE *r, f
>     }
> 
>   if (fmt.decimal_p ())
> -    decimal_from_integer (r);
> +    /* We need at most one decimal digits for each 3 bits of input
> +       precision.  */
> +    decimal_from_integer (r, val_in.get_precision () / 3);
>   if (fmt)
>     real_convert (r, fmt, r);
> }
> @@ -2364,12 +2366,21 @@ decimal_integer_string (char *str, const
> /* Convert a real with an integral value to decimal float.  */
> 
> static void
> -decimal_from_integer (REAL_VALUE_TYPE *r)
> +decimal_from_integer (REAL_VALUE_TYPE *r, int digits)
> {
>   char str[256];
> 
> -  decimal_integer_string (str, r, sizeof (str) - 1);
> -  decimal_real_from_string (r, str);
> +  if (digits <= 256)
> +    {
> +      decimal_integer_string (str, r, sizeof (str) - 1);
> +      decimal_real_from_string (r, str);
> +    }
> +  else
> +    {
> +      char *s = XALLOCAVEC (char, digits);
> +      decimal_integer_string (s, r, digits - 1);
> +      decimal_real_from_string (r, s);
> +    }
> }
> 
> /* Returns 10**2**N.  */
> --- gcc/dfp.cc.jj    2025-04-08 14:08:50.669289967 +0200
> +++ gcc/dfp.cc    2025-06-17 17:28:25.101792744 +0200
> @@ -619,11 +619,21 @@ decimal_real_to_integer (const REAL_VALU
>   decNumber dn, dn2, dn3;
>   REAL_VALUE_TYPE to;
>   char string[256];
> +  int scale = 0;
> 
>   decContextDefault (&set, DEC_INIT_DECIMAL128);
>   set.traps = 0;
>   set.round = DEC_ROUND_DOWN;
>   decimal128ToNumber ((const decimal128 *) r->sig, &dn);
> +  if (precision > 128 && decNumberIsFinite (&dn) && dn.exponent > 19)
> +    {
> +      /* libdecNumber doesn't really handle too large integers.
> +     So when precision is large and exponent as well, trim the
> +     exponent and adjust the resulting wide_int by multiplying
> +     it multiple times with 10^19.  */
> +      scale = dn.exponent / 19;
> +      dn.exponent %= 19;
> +    }
> 
>   decNumberToIntegralValue (&dn2, &dn, &set);
>   decNumberZero (&dn3);
> @@ -633,7 +643,44 @@ decimal_real_to_integer (const REAL_VALU
>      function.  */
>   decNumberToString (&dn, string);
>   real_from_string (&to, string);
> -  return real_to_integer (&to, fail, precision);
> +  bool failp = false;
> +  wide_int w = real_to_integer (&to, &failp, precision);
> +  if (failp)
> +    *fail = true;
> +  if (scale && !failp)
> +    {
> +      wide_int wm = wi::uhwi (HOST_WIDE_INT_UC (10000000000000000000),
> +                  w.get_precision ());
> +      bool isneg = wi::neg_p (w);
> +      if (isneg)
> +    w = -w;
> +      enum wi::overflow_type ovf = wi::OVF_NONE;
> +      do
> +    {
> +      if (scale & 1)
> +        {
> +          w = wi::umul (w, wm, &ovf);
> +          if (ovf)
> +        break;
> +        }
> +      scale >>= 1;
> +      if (!scale)
> +        break;
> +      wm = wi::umul (wm, wm, &ovf);
> +    }
> +      while (!ovf);
> +      if (ovf)
> +    {
> +      *fail = true;
> +      if (isneg)
> +        return wi::set_bit_in_zero (precision - 1, precision);
> +      else
> +        return ~wi::set_bit_in_zero (precision - 1, precision);
> +    }
> +      if (isneg)
> +    w = -w;
> +    }
> +  return w;
> }
> 
> /* Perform the decimal floating point operation described by CODE.
> --- gcc/testsuite/gcc.dg/dfp/bitint-9.c.jj    2025-06-17 17:30:13.271374809 
> +0200
> +++ gcc/testsuite/gcc.dg/dfp/bitint-9.c    2025-06-17 14:53:36.997994620 +0200
> @@ -0,0 +1,29 @@
> +/* PR middle-end/120631 */
> +/* { dg-do run { target bitint } } */
> +/* { dg-options "-O2" } */
> +
> +#if __BITINT_MAXWIDTH__ >= 2048
> +_Decimal128 a = 
> 123456789135792468012345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0dl;
> +_BitInt(2048) b = 
> 123456789135792468012345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000wb;
> +_Decimal64 c = 
> 123456789135790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0dd;
> +_BitInt(1536) d = 
> 123456789135790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000wb;
> +#endif
> +
> +int
> +main ()
> +{
> +#if __BITINT_MAXWIDTH__ >= 2048
> +  if (a != b || (_BitInt(2048)) a != b || c != d || (_BitInt(1536)) c != d)
> +    __builtin_abort ();
> +  _Decimal128 e = 
> 123456789135792468012345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0dl;
> +  _BitInt(2048) f = 
> 123456789135792468012345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000wb;
> +  _Decimal128 g = 
> 123456789135792468012345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000wb;
> +  _BitInt(2048) h = 
> 123456789135792468012345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0dl;
> +  _Decimal64 i = 
> 123456789135790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0dd;
> +  _BitInt(1536) j = 
> 123456789135790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000wb;
> +  _Decimal64 k = 
> 123456789135790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000wb;
> +  _BitInt(1536) l = 
> 123456789135790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0dd;
> +  if (e != g || f != h || i != k || j != l)
> +    __builtin_abort ();
> +#endif
> +}
> 
>    Jakub
> 

Reply via email to