https://gcc.gnu.org/g:30886aeca75076bfd50b0fff8d76942603bee763

commit r16-7377-g30886aeca75076bfd50b0fff8d76942603bee763
Author: Roger Sayle <[email protected]>
Date:   Sat Feb 7 08:04:40 2026 +0000

    PR tree-optimization/123958: FMA vs pow(x,2.0) [vs errno]
    
    This is my proposed solution to PR123958 (and PR124002) which is a
    regression exposed by my recent change to avoid expanding pow(x,2.0)
    to x*x with -fmath-errno (the default) when we can't guarantee that
    errno shouldn't be updated.  The problem is that the logic to convert
    pow(x,2.0) was also duplicated (but unused) in tree-ssa-math-opts
    where it's intended to perform this conversion in order to expose
    fused-multiply-add instructions when supported by the target.  The
    issue is that this "vestigial" code has bit-rotten over the years,
    and incorrectly updates vdefs when changing vops, tiggering an ICE.
    
    My pragmatic solution to this is to simply delete the problematic
    code; the decision of whether pow(x,2.0) should be expanded is left
    to the earlier pow_expand pass (which is what it's designed for), and
    the later FMA pass can make use of any resulting FP multiplications.
    Not only does this avoid the PHI related ICE, but also fixes the
    original PR (on updating errno) on targets with FMA, e.g. aarch64
    and recent x86_64 architectures (such as -march=znver3).
    
    2026-02-07  Roger Sayle  <[email protected]>
    
    gcc/ChangeLog
            PR middle-end/123826
            PR tree-optimization/123958
            PR c++/124002
            * tree-ssa-math-opts.cc (math_opts_dom_walker::after_dom_children):
            Delete code that (mis)handled conversion of pow(x,2.0) to x*x.
    
    gcc/testsuite/ChangeLog
            PR middle-end/123826
            PR tree-optimization/123958
            PR c++/124002
            * g++.target/i386/pr124002.C: New test case.
            * gcc.target/i386/pr123958.c: Likewise.
            * gcc.dg/errno-4.c: Likewise.

Diff:
---
 gcc/testsuite/g++.target/i386/pr124002.C | 15 ++++++++++++++
 gcc/testsuite/gcc.dg/errno-4.c           | 35 ++++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr123958.c | 18 ++++++++++++++++
 gcc/tree-ssa-math-opts.cc                | 19 -----------------
 4 files changed, 68 insertions(+), 19 deletions(-)

diff --git a/gcc/testsuite/g++.target/i386/pr124002.C 
b/gcc/testsuite/g++.target/i386/pr124002.C
new file mode 100644
index 000000000000..033cd3de870e
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr124002.C
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=znver3" } */
+
+extern "C" double pow(double, double);
+double sigmoid_x;
+double sigmoid() {
+  if (sigmoid_x)
+    return sigmoid_x;
+  return 0;
+}
+double der_sigmoid() {
+  double tmp = sigmoid();
+  return tmp - pow(tmp, 2);
+}
+
diff --git a/gcc/testsuite/gcc.dg/errno-4.c b/gcc/testsuite/gcc.dg/errno-4.c
new file mode 100644
index 000000000000..d7b80c1ca418
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/errno-4.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 <errno.h>
+#include <float.h>
+#include <math.h>
+
+double foo(double x)
+{
+  return x + 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.target/i386/pr123958.c 
b/gcc/testsuite/gcc.target/i386/pr123958.c
new file mode 100644
index 000000000000..75064e880b4f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr123958.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=znver3" } */
+
+float fnk00xX_rae1_1;
+double pow(double, double);
+double sqrt(double);
+void write_r4(float *);
+void fnk00xX() {
+  int i;
+  float rs2;
+  double ds2;
+  for (; i; i += 1) {
+    sqrt(i);
+    ds2 = ds2 + pow(fnk00xX_rae1_1, 2.0);
+    rs2 = ds2;
+  }
+  write_r4(&rs2);
+}
diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc
index 1655b68cb9c6..6d69711fffbd 100644
--- a/gcc/tree-ssa-math-opts.cc
+++ b/gcc/tree-ssa-math-opts.cc
@@ -6623,25 +6623,6 @@ math_opts_dom_walker::after_dom_children (basic_block bb)
        {
          switch (gimple_call_combined_fn (stmt))
            {
-           CASE_CFN_POW:
-             if (gimple_call_lhs (stmt)
-                 && TREE_CODE (gimple_call_arg (stmt, 1)) == REAL_CST
-                 && real_equal (&TREE_REAL_CST (gimple_call_arg (stmt, 1)),
-                                &dconst2)
-                 && convert_mult_to_fma (stmt,
-                                         gimple_call_arg (stmt, 0),
-                                         gimple_call_arg (stmt, 0),
-                                         &fma_state))
-               {
-                 unlink_stmt_vdef (stmt);
-                 if (gsi_remove (&gsi, true)
-                     && gimple_purge_dead_eh_edges (bb))
-                   *m_cfg_changed_p = true;
-                 release_defs (stmt);
-                 continue;
-               }
-             break;
-
            case CFN_COND_MUL:
              if (convert_mult_to_fma (stmt,
                                       gimple_call_arg (stmt, 1),

Reply via email to