The problem here was a missing save_expr around arg0 since
it is used twice, once in REALPART_EXPR and once in IMAGPART_EXPR.
Thia adds the save_expr and reformats the code slightly so it is a
little easier to understand.  It excludes the case when arg0 is
a COMPLEX_EXPR since in that case we'll end up with the distinct
real and imaginary parts.  This is important to retain early
optimization in some testcases.

Bootstapped and tested on x86_64-linux-gnu with no regressions, pushed.

        PR 116454

gcc/ChangeLog:

        * fold-const.cc (fold_binary_loc): Fix `a * +-1i`
        by wrapping arg0 with save_expr when it is not COMPLEX_EXPR.

gcc/testsuite/ChangeLog:

        * gcc.dg/torture/pr116454-1.c: New test.
        * gcc.dg/torture/pr116454-2.c: New test.

Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com>
Co-Authored-By: Richard Biener  <rguent...@suse.de>
---
 gcc/fold-const.cc                         | 32 ++++++++++++++++-------
 gcc/testsuite/gcc.dg/torture/pr116454-1.c | 16 ++++++++++++
 gcc/testsuite/gcc.dg/torture/pr116454-2.c | 12 +++++++++
 3 files changed, 50 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr116454-1.c
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr116454-2.c

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index eeadc8db9f6..35402a59768 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -12093,17 +12093,29 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
            {
              tree rtype = TREE_TYPE (TREE_TYPE (arg0));
              if (real_onep (TREE_IMAGPART (arg1)))
-               return
-                 fold_build2_loc (loc, COMPLEX_EXPR, type,
-                              negate_expr (fold_build1_loc (loc, IMAGPART_EXPR,
-                                                            rtype, arg0)),
-                              fold_build1_loc (loc, REALPART_EXPR, rtype, 
arg0));
+               {
+                 if (TREE_CODE (arg0) != COMPLEX_EXPR)
+                   arg0 = save_expr (arg0);
+                 tree iarg0 = fold_build1_loc (loc, IMAGPART_EXPR,
+                                               rtype, arg0);
+                 tree rarg0 = fold_build1_loc (loc, REALPART_EXPR,
+                                               rtype, arg0);
+                 return fold_build2_loc (loc, COMPLEX_EXPR, type,
+                                         negate_expr (iarg0),
+                                         rarg0);
+               }
              else if (real_minus_onep (TREE_IMAGPART (arg1)))
-               return
-                 fold_build2_loc (loc, COMPLEX_EXPR, type,
-                              fold_build1_loc (loc, IMAGPART_EXPR, rtype, 
arg0),
-                              negate_expr (fold_build1_loc (loc, REALPART_EXPR,
-                                                            rtype, arg0)));
+               {
+                 if (TREE_CODE (arg0) != COMPLEX_EXPR)
+                   arg0 = save_expr (arg0);
+                 tree iarg0 = fold_build1_loc (loc, IMAGPART_EXPR,
+                                               rtype, arg0);
+                 tree rarg0 = fold_build1_loc (loc, REALPART_EXPR,
+                                               rtype, arg0);
+                 return fold_build2_loc (loc, COMPLEX_EXPR, type,
+                                         iarg0,
+                                         negate_expr (rarg0));
+               }
            }
 
          /* Optimize z * conj(z) for floating point complex numbers.
diff --git a/gcc/testsuite/gcc.dg/torture/pr116454-1.c 
b/gcc/testsuite/gcc.dg/torture/pr116454-1.c
new file mode 100644
index 00000000000..6210dcce4a4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr116454-1.c
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-additional-options "-ffast-math" } */
+
+static int t = 0;
+_Complex float f()
+{
+        t++;
+        return 0;
+}
+int main() {
+       t = 0;
+       /* Would cause f() to be incorrectly invoked twice. */
+       f() * 1j;
+       if (t != 1)
+          __builtin_abort();
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr116454-2.c 
b/gcc/testsuite/gcc.dg/torture/pr116454-2.c
new file mode 100644
index 00000000000..a1e1604e616
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr116454-2.c
@@ -0,0 +1,12 @@
+/* { dg-do run } */
+/* { dg-additional-options "-ffast-math" } */
+_Complex float arr[2];
+
+int main() {
+  _Complex float *ptr;
+  ptr = arr;
+  *++ptr * 1j; 
+  /* ptr should only increment once, not twice. */
+  if (ptr != arr + 1)
+    __builtin_abort ();
+}
-- 
2.43.0

Reply via email to