diff mbox series

fold: Fix `a * 1j` if a has side effects [PR116454]

Message ID 20240822114645.85F783870C2E@sourceware.org
State New
Headers show
Series fold: Fix `a * 1j` if a has side effects [PR116454] | expand

Commit Message

Andrew Pinski Aug. 22, 2024, 11:46 a.m. UTC
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_apinski@quicinc.com>
Co-Authored-By: Richard Biener  <rguenther@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 mbox series

Patch

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 ();
+}