https://gcc.gnu.org/g:b07f8a301158e53717b8688cc8ea430b6f02574c

commit r15-3087-gb07f8a301158e53717b8688cc8ea430b6f02574c
Author: Andrew Pinski <quic_apin...@quicinc.com>
Date:   Wed Aug 21 17:41:38 2024 -0700

    fold: Fix `a * 1j` if a has side effects [PR116454]
    
    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.
    
            PR middle-end/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>

Diff:
---
 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(-)

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 8908e7381e72..ccc499af6617 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 000000000000..6210dcce4a42
--- /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 000000000000..a1e1604e6169
--- /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 ();
+}

Reply via email to