[PATCH] PR middle-end/126775: ICE optimizing (T)0.0 - x with -ffinite-math-only

"Roger Sayle" <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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
--
patchrn4.txt (text/plain, 2.1 KB)
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.