]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c, c++: Set DECL_NOT_GIMPLE_REG_P on *PART_EXPR operand on lhs of MODIFY_EXPR [PR119120]
authorJakub Jelinek <jakub@redhat.com>
Fri, 14 Mar 2025 14:31:47 +0000 (15:31 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 14 Mar 2025 14:31:47 +0000 (15:31 +0100)
The PR119190 patch I've posted regresses the PR119120 testcase (not adding
to testsuite, as it is fairly hard to scan for that problem).
The issue is that for the partial setting of _Complex floating vars
through __real__ on it first and __imag__ later (or vice versa) and since
we forced all complex vars into SSA form we often have undefined (D)
arguments of those COMPLEX_EXPRs.  When we don't DCE them (for -O0 debug
info reasons), their expansion will copy both the real and imag parts
using the floating mode and on some targets like 387 that copying alone can
unfortunately trigger exceptions on sNaNs or other problematic bit patterns
and for uninitialized memory it can be triggered randomly based on whatever
is on the stack before.

The following patch sets DECL_NOT_GIMPLE_REG_P flag in the FEs during
genericization.
I think Fortran doesn't have a way to modify just real or just complex
part separately.

The patch is for code like
          _ComplexT __t;
          __real__ __t = __z.real();
          __imag__ __t = __z.imag();
          _M_value *= __t;
          return *this;
at -O0 which used to appear widely even in libstdc++ before GCC 9
and happens in real-world code.  At -O0 for debug info reasons (see
PR119190) we don't want to aggressively DCE statements and when we
since r0-100845 try to rewrite vars with COMPLEX_TYPE into SSA form
aggressively, the above results in copying of uninitialized data
when expanding COMPLEX_EXPRs added so that the vars can be in SSA form.
The patch detects during genericization the partial initialization and
doesn't rewrite such vars to SSA at -O0.  This has to be done before
gimplification starts, otherwise e.g. the attached testcase ICEs.

2025-03-14  Jakub Jelinek  <jakub@redhat.com>

PR target/119120
* c-gimplify.cc (c_genericize_control_r): Set DECL_NOT_GIMPLE_REG_P
on {REAL,IMAG}PART_EXPR is_gimple_reg operand at -O0 if it is lhs
of a MODIFY_EXPR.

* cp-gimplify.cc (cp_genericize_r): Set DECL_NOT_GIMPLE_REG_P
on {REAL,IMAG}PART_EXPR is_gimple_reg operand at -O0 if it is lhs
of a MODIFY_EXPR.

* c-c++-common/pr119120.c: New test.

gcc/c-family/c-gimplify.cc
gcc/cp/cp-gimplify.cc
gcc/testsuite/c-c++-common/pr119120.c [new file with mode: 0644]

index dc5e80dfa6bea9314dea74f0434c1d3bd5baebb8..c6fb7646567e14d89d58b5c9e36bc88eda19f8a8 100644 (file)
@@ -727,6 +727,18 @@ c_genericize_control_stmt (tree *stmt_p, int *walk_subtrees, void *data,
 static tree
 c_genericize_control_r (tree *stmt_p, int *walk_subtrees, void *data)
 {
+  tree stmt = *stmt_p;
+  /* Mark stores to parts of complex automatic non-addressable
+     variables as DECL_NOT_GIMPLE_REG_P for -O0.  This can't be
+     done during gimplification.  See PR119120.  */
+  if (TREE_CODE (stmt) == MODIFY_EXPR
+      && (TREE_CODE (TREE_OPERAND (stmt, 0)) == REALPART_EXPR
+         || TREE_CODE (TREE_OPERAND (stmt, 0)) == IMAGPART_EXPR)
+      && !optimize
+      && DECL_P (TREE_OPERAND (TREE_OPERAND (stmt, 0), 0))
+      && is_gimple_reg (TREE_OPERAND (TREE_OPERAND (stmt, 0), 0)))
+    DECL_NOT_GIMPLE_REG_P (TREE_OPERAND (TREE_OPERAND (stmt, 0), 0)) = 1;
+
   c_genericize_control_stmt (stmt_p, walk_subtrees, data,
                             c_genericize_control_r, NULL);
   return NULL;
index 45f4e27b8b742b3f674baf1025d383ea95cbceb4..04e430801d5f71e44e5bdfa902dc4b039fdb27f1 100644 (file)
@@ -2277,6 +2277,18 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
                            TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
       break;
 
+    case MODIFY_EXPR:
+      /* Mark stores to parts of complex automatic non-addressable
+        variables as DECL_NOT_GIMPLE_REG_P for -O0.  This can't be
+        done during gimplification.  See PR119120.  */
+      if ((TREE_CODE (TREE_OPERAND (stmt, 0)) == REALPART_EXPR
+          || TREE_CODE (TREE_OPERAND (stmt, 0)) == IMAGPART_EXPR)
+         && !optimize
+         && DECL_P (TREE_OPERAND (TREE_OPERAND (stmt, 0), 0))
+         && is_gimple_reg (TREE_OPERAND (TREE_OPERAND (stmt, 0), 0)))
+       DECL_NOT_GIMPLE_REG_P (TREE_OPERAND (TREE_OPERAND (stmt, 0), 0)) = 1;
+      break;
+
     default:
       if (IS_TYPE_OR_DECL_P (stmt))
        *walk_subtrees = 0;
diff --git a/gcc/testsuite/c-c++-common/pr119120.c b/gcc/testsuite/c-c++-common/pr119120.c
new file mode 100644 (file)
index 0000000..1b1074e
--- /dev/null
@@ -0,0 +1,40 @@
+/* PR target/119120 */
+/* { dg-do compile } */
+/* { dg-options "-O0 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump "REALPART_EXPR <r> = " "optimized" } } */
+/* { dg-final { scan-tree-dump "IMAGPART_EXPR <r> = " "optimized" } } */
+/* { dg-final { scan-tree-dump "REALPART_EXPR <s> = " "optimized" } } */
+/* { dg-final { scan-tree-dump-not "(REAL|IMAG)PART_EXPR <t> = " "optimized" } } */
+/* { dg-final { scan-tree-dump-not "(REAL|IMAG)PART_EXPR <u> = " "optimized" } } */
+
+__complex__ double
+foo (void)
+{
+  __complex__ double r;
+  __imag__ r = 2.0;
+  __real__ r = 1.0;
+  return r + 1.0;
+}
+
+__complex__ float
+bar (float x, float y)
+{
+  __complex__ float s = x + y * 1.0fi;
+  __real__ s = 1.0f;
+  return s + 1.0f;
+}
+
+__complex__ float
+baz (float x, float y)
+{
+  __complex__ float t = x + y * 1.0fi;
+  return t + 1.0f;
+}
+
+__complex__ float
+qux (__complex__ float x)
+{
+  __complex__ float u;
+  u = x;
+  return u + 1.0f;
+}