https://gcc.gnu.org/g:f39e6b4f5cd4e5362cf4b1004a591df2c8b00304
commit r15-5671-gf39e6b4f5cd4e5362cf4b1004a591df2c8b00304 Author: Jakub Jelinek <ja...@redhat.com> Date: Tue Nov 26 09:45:21 2024 +0100 builtins: Fix up DFP ICEs on __builtin_is{inf,finite,normal} [PR43374] __builtin_is{inf,finite,normal} builtins ICE on _Decimal{32,64,128,64x} operands unless those operands are constant. The problem is that we fold the builtins to comparisons with the largest finite number, but a) get_max_float was only handling binary floats b) real_from_string again assumes binary float and so we were ICEing in the build_real called after the two calls. This patch adds decimal handling into get_max_float (well, moves it from c-cppbuiltin.cc which was printing those for __DEC{32,64,128}_MAX__ macros) and uses real_from_string3 (perhaps it is time to rename it to just real_from_string now that we can use function overloading) so that it handles both binary and decimal floats. 2024-11-26 Jakub Jelinek <ja...@redhat.com> PR middle-end/43374 gcc/ * real.cc (get_max_float): Handle decimal float. * builtins.cc (fold_builtin_interclass_mathfn): Use real_from_string3 rather than real_from_string. Use "1E%d" format string rather than "0x1p%d" for decimal float minimum. gcc/c-family/ * c-cppbuiltin.cc (builtin_define_decimal_float_constants): Use get_max_float. gcc/testsuite/ * gcc.dg/dfp/pr43374.c: New test. Diff: --- gcc/builtins.cc | 13 +++++---- gcc/c-family/c-cppbuiltin.cc | 13 ++------- gcc/real.cc | 16 +++++++++++ gcc/testsuite/gcc.dg/dfp/pr43374.c | 56 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 16 deletions(-) diff --git a/gcc/builtins.cc b/gcc/builtins.cc index 029c561d4665..055b31d264ca 100644 --- a/gcc/builtins.cc +++ b/gcc/builtins.cc @@ -9580,7 +9580,7 @@ fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg) arg = fold_build1_loc (loc, NOP_EXPR, type, arg); } get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf), false); - real_from_string (&r, buf); + real_from_string3 (&r, buf, mode); result = build_call_expr (isgr_fn, 2, fold_build1_loc (loc, ABS_EXPR, type, arg), build_real (type, r)); @@ -9604,7 +9604,7 @@ fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg) arg = fold_build1_loc (loc, NOP_EXPR, type, arg); } get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf), false); - real_from_string (&r, buf); + real_from_string3 (&r, buf, mode); result = build_call_expr (isle_fn, 2, fold_build1_loc (loc, ABS_EXPR, type, arg), build_real (type, r)); @@ -9643,9 +9643,12 @@ fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg) arg = fold_build1_loc (loc, ABS_EXPR, type, arg); get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf), false); - real_from_string (&rmax, buf); - sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (orig_mode)->emin - 1); - real_from_string (&rmin, buf); + real_from_string3 (&rmax, buf, mode); + if (DECIMAL_FLOAT_MODE_P (mode)) + sprintf (buf, "1E%d", REAL_MODE_FORMAT (orig_mode)->emin - 1); + else + sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (orig_mode)->emin - 1); + real_from_string3 (&rmin, buf, orig_mode); max_exp = build_real (type, rmax); min_exp = build_real (type, rmin); diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index 349918c325cd..8fbfef561e8a 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -357,17 +357,8 @@ builtin_define_decimal_float_constants (const char *name_prefix, /* Compute the maximum representable value. */ sprintf (name, "__%s_MAX__", name_prefix); - p = buf; - for (digits = fmt->p; digits; digits--) - { - *p++ = '9'; - if (digits == fmt->p) - *p++ = '.'; - } - *p = 0; - /* fmt->p plus 1, to account for the decimal point and fmt->emax - minus 1 because the digits are nines, not 1.0. */ - sprintf (&buf[fmt->p + 1], "E%d%s", fmt->emax - 1, suffix); + get_max_float (fmt, buf, sizeof (buf) - strlen (suffix), false); + strcat (buf, suffix); builtin_define_with_value (name, buf, 0); /* Compute epsilon (the difference between 1 and least value greater diff --git a/gcc/real.cc b/gcc/real.cc index 1392595a72f1..b89ff8334091 100644 --- a/gcc/real.cc +++ b/gcc/real.cc @@ -5438,6 +5438,22 @@ void get_max_float (const struct real_format *fmt, char *buf, size_t len, bool norm_max) { + if (fmt->b == 10) + { + char *p = buf; + for (int i = fmt->p; i; i--) + { + *p++ = '9'; + if (i == fmt->p) + *p++ = '.'; + } + /* fmt->p plus 1, to account for the decimal point and fmt->emax + minus 1 because the digits are nines, not 1.0. */ + sprintf (buf + fmt->p + 1, "E%d", fmt->emax - 1); + gcc_assert (strlen (buf) < len); + return; + } + int i, n; char *p; bool is_ibm_extended = fmt->pnan < fmt->p; diff --git a/gcc/testsuite/gcc.dg/dfp/pr43374.c b/gcc/testsuite/gcc.dg/dfp/pr43374.c new file mode 100644 index 000000000000..83f3dca1c1f2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/dfp/pr43374.c @@ -0,0 +1,56 @@ +/* PR middle-end/43374 */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +__attribute__((noipa)) int +foo (_Decimal32 x) +{ + return __builtin_isinf (x); +} + +__attribute__((noipa)) int +bar (_Decimal64 x) +{ + return __builtin_isfinite (x); +} + +__attribute__((noipa)) int +baz (_Decimal128 x) +{ + return __builtin_isnormal (x); +} + +int +main () +{ + if (!foo (__builtin_infd32 ()) + || !foo (-__builtin_infd32 ()) + || foo (__builtin_nand32 ("")) + || foo (9.999999E96DF) + || foo (-1E-95DF) + || foo (0.999999E-95DF) + || foo (-0.000001E-95DF) + || foo (0.000DF) + || foo (-0.00000DF)) + __builtin_abort (); + if (bar (__builtin_infd64 ()) + || bar (-__builtin_infd64 ()) + || bar (__builtin_nand64 ("")) + || !bar (9.999999999999999E384DD) + || !bar (-1E-383DD) + || !bar (0.999999999999999E-383DD) + || !bar (-0.000000000000001E-383DD) + || !bar (0.000DD) + || !bar (-0.0000000000DD)) + __builtin_abort (); + if (baz (__builtin_infd128 ()) + || baz (-__builtin_infd128 ()) + || baz (__builtin_nand128 ("")) + || !baz (9.999999999999999999999999999999999E6144DL) + || !baz (-1E-6143DL) + || baz (0.999999999999999999999999999999999E-6143DL) + || baz (-0.000000000000000000000000000000001E-6143DL) + || baz (0.000DL) + || baz (-0.0000000000000000000000DL)) + __builtin_abort (); +}