This patch fixes PR middle-end/126775, an ICE caused by my recent change
to match.pd around tweaking the conditions under which 0.0 - x can
safely be transformed into -x.  Unfortunately, that change assumed
that real_zerop@0 implies that TREE_CODE(@0) == REAL_CST.  Alas things
aren't that simple, so this fix introduces a new real_negzerop predicate
that in addition to REAL_CST also handles VECTOR_CST and COMPLEX_CST,
and most importantly fails gracefully on TREE_CODEs that it isn't
expecting.

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-08-19  Roger Sayle  <[email protected]>

gcc/ChangeLog
        PR middle-end/126775
        * match.pd (0.0 - x -> -x): Use new real_negzerop function.
        * tree.cc (real_negzerop): New predicate function to test if
        a tree expression is -0.0 or equivalent (like real_zerop).
        * tree.h (real_negzerop): Prototype here.

gcc/testsuite/ChangeLog
        PR middle-end/126775
        * gcc.dg/pr126775.c: New test case.


Thanks again, and apologies for any inconvenice.
Roger
--

diff --git a/gcc/match.pd b/gcc/match.pd
index 1ea46fd1726..5888a2f167f 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -6014,7 +6014,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       && (!HONOR_SIGNED_ZEROS (type)
          || tree_expr_nonzero_p (@1)
          || (!flag_rounding_math
-             && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@0)))))
+             && real_negzerop (@0))))
   (negate @1)))
 
 /* Transform x * -1 into -x.  */
diff --git a/gcc/testsuite/gcc.dg/pr126775.c b/gcc/testsuite/gcc.dg/pr126775.c
new file mode 100644
index 00000000000..12eb8078b15
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr126775.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ffinite-math-only" } */
+
+_Complex float foo(_Complex float x)
+{
+  _Complex float negzero = -0.0f + -0.0fi;
+  return negzero - x;
+}
diff --git a/gcc/tree.cc b/gcc/tree.cc
index c8aa42b3e10..8bc5fb52a27 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3326,6 +3326,29 @@ real_zerop (const_tree expr)
     }
 }
 
+/* Return true if EXPR is the real constant negative zero.  */
+
+bool
+real_negzerop (const_tree expr)
+{
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
+  if (TREE_CODE (expr) == VECTOR_CST)
+    {
+      expr = uniform_vector_p (expr);
+      if (!expr)
+       return false;
+    }
+
+  if (TREE_CODE (expr) == COMPLEX_CST)
+    return real_negzerop (TREE_REALPART (expr))
+          && real_negzerop (TREE_IMAGPART (expr));
+
+  return TREE_CODE (expr) == REAL_CST
+         && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (expr))
+         && !(DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (expr))));
+}
+
 /* Return true if EXPR is the real constant one in real or complex form.
    Trailing zeroes matter for decimal float constants, so don't return
    true for them.
diff --git a/gcc/tree.h b/gcc/tree.h
index 1ccbf848d9b..c7f394644dd 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5688,6 +5688,9 @@ extern tree decl_type_context (const_tree);
 /* Return true if EXPR is the real constant zero.  */
 extern bool real_zerop (const_tree);
 
+/* Return true if EXPR is the real constant negative zero.  */
+extern bool real_negzerop (const_tree);
+
 /* Initialize the iterator I with arguments from function FNDECL  */
 
 inline void

Reply via email to