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.

This patch has been tested on x86_64-pc-linux-gnu with make bootstrap
and make -k check, both with and without --target_board=unix{-m32},
with no new failures.  Ok for mainline?


2026-02-02  Roger Sayle  <[email protected]>

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..2efd4be9790
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/errno-2.c
@@ -0,0 +1,22 @@
+/* PR middle-end/123826 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#include <errno.h>
+#include <float.h>
+#include <math.h>
+
+double foo(double x)
+{
+  return pow(x, 2.0);
+}
+
+int main()
+{
+  errno = 0;
+  double x = foo(DBL_MAX);
+  if (errno != ERANGE)
+    __builtin_abort ();
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/errno-3.c b/gcc/testsuite/gcc.dg/errno-3.c
new file mode 100644
index 00000000000..7f0ecda2d7c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/errno-3.c
@@ -0,0 +1,22 @@
+/* PR middle-end/123826 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#include <errno.h>
+#include <float.h>
+#include <math.h>
+
+float foo(float x)
+{
+  return powf(x, 2.0f);
+}
+
+int main()
+{
+  errno = 0;
+  float x = foo(FLT_MAX);
+  if (errno != ERANGE)
+    __builtin_abort ();
+  return 0;
+}
+
diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc
index 4c3fb0f4fc5..0a2d6d0120e 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);

Reply via email to