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