From: Roger Sayle Date: Tue, 3 Feb 2026 17:06:25 +0000 (+0000) Subject: PR middle-end/123826: __builtin_pow vs. errno. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a70bdd86984c0b6cd8520e30ec713e3101c5d45f;p=thirdparty%2Fgcc.git PR middle-end/123826: __builtin_pow vs. errno. This is my proposed solution to PR middle-end/123826. Initially I thought this would be a "one line change", adding a test for flag_errno_math to gimple_expand_builtin_pow. Unfortunately this revealed a second later problem, where pow (with constant arguments) was still getting evaluated at compile-time, even when the result is known to overflow. It's ancient history, but shortly after I added support for pow as a builtin, I contributed code to evaluate it at compile-time when the exponent is an integer constant. Since then we now use MPFR to evaluate libm math functions at compile-time. However the vestigial call to evaluate pow via real_powi still exists, and gets invoked after do_mpfr_arg2/mpfr_pow correctly determines that we shouldn't evaluate pow at compile-time. This patch reorganizes fold_const_pow paying attention to signaling NaNs (PR 61441) and flag_errno_math. Most importantly normal cases like pow(2.0,3.0) and pow(3.0,0.5) still get evaluated at compile-time. 2026-02-03 Roger Sayle gcc/ChangeLog PR middle-end/123826 * tree-ssa-math-opts.cc (gimple_expand_builtin_pow): Add test for flag_errno_math. * fold-const-call.cc (fold_const_pow): Reorganize, eliminating call to real_powi, and letting do_mpfr_arg2 do all the heavy lifting. gcc/testsuite/ChangeLog PR middle-end/123826 * gcc.dg/errno-2.c: New test case. * gcc.dg/errno-3.c: Likewise. --- diff --git a/gcc/fold-const-call.cc b/gcc/fold-const-call.cc index aa63ced00bb..7dd1b21c34f 100644 --- a/gcc/fold-const-call.cc +++ b/gcc/fold-const-call.cc @@ -495,27 +495,25 @@ static bool fold_const_pow (real_value *result, const real_value *arg0, const real_value *arg1, const real_format *format) { + if (flag_signaling_nans + && (REAL_VALUE_ISSIGNALING_NAN (*arg0) + || REAL_VALUE_ISSIGNALING_NAN (*arg1))) + return false; + if (do_mpfr_arg2 (result, mpfr_pow, arg0, arg1, format)) - return true; - - /* Check for an integer exponent. */ - REAL_VALUE_TYPE cint1; - HOST_WIDE_INT n1 = real_to_integer (arg1); - real_from_integer (&cint1, VOIDmode, n1, SIGNED); - /* Attempt to evaluate pow at compile-time, unless this should - raise an exception. */ - if (real_identical (arg1, &cint1) - && (n1 > 0 - || (!flag_trapping_math && !flag_errno_math) - || !real_equal (arg0, &dconst0))) { - bool inexact = real_powi (result, format, arg0, n1); - /* Avoid the folding if flag_signaling_nans is on. */ - if (flag_unsafe_math_optimizations - || (!inexact - && !(flag_signaling_nans - && REAL_VALUE_ISSIGNALING_NAN (*arg0)))) - return true; + if (flag_errno_math) + switch (result->cl) + { + case rvc_inf: + case rvc_nan: + return false; + case rvc_zero: + return arg0->cl == rvc_zero; + default: + break; + } + return true; } return false; diff --git a/gcc/testsuite/gcc.dg/errno-2.c b/gcc/testsuite/gcc.dg/errno-2.c new file mode 100644 index 00000000000..b7e7917e35a --- /dev/null +++ b/gcc/testsuite/gcc.dg/errno-2.c @@ -0,0 +1,35 @@ +/* PR middle-end/123826 */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#ifdef __NO_MATH_ERRNO__ +int main() { return 0; } +#else +#include +#include +#include + +double foo(double x) +{ + return pow(x, 2.0); +} + +int main() +{ +#ifdef math_errhandling +#ifdef MATH_ERRNO + if ((math_errhandling & MATH_ERRNO) == 0) + return 0; +#else + if ((math_errhandling & 1) == 0) + return 0; +#endif +#endif + + errno = 0; + double x = foo(DBL_MAX); + if (errno != ERANGE) + __builtin_abort (); + return 0; +} +#endif diff --git a/gcc/testsuite/gcc.dg/errno-3.c b/gcc/testsuite/gcc.dg/errno-3.c new file mode 100644 index 00000000000..df985b2091d --- /dev/null +++ b/gcc/testsuite/gcc.dg/errno-3.c @@ -0,0 +1,35 @@ +/* PR middle-end/123826 */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#ifdef __NO_MATH_ERRNO__ +int main() { return 0; } +#else +#include +#include +#include + +float foo(float x) +{ + return powf(x, 2.0f); +} + +int main() +{ +#ifdef math_errhandling +#ifdef MATH_ERRNO + if ((math_errhandling & MATH_ERRNO) == 0) + return 0; +#else + if ((math_errhandling & 1) == 0) + return 0; +#endif +#endif + + errno = 0; + float x = foo(FLT_MAX); + if (errno != ERANGE) + __builtin_abort (); + return 0; +} +#endif diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc index 74dc94c9626..469de10a432 100644 --- a/gcc/tree-ssa-math-opts.cc +++ b/gcc/tree-ssa-math-opts.cc @@ -2029,6 +2029,9 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *gsi, location_t loc, || REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg1)))) return NULL_TREE; + if (flag_errno_math) + return NULL_TREE; + /* If the exponent is equivalent to an integer, expand to an optimal multiplication sequence when profitable. */ c = TREE_REAL_CST (arg1);