aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAndrew Pinski <quic_apinski@quicinc.com>2024-08-21 17:41:38 -0700
committerRichard Biener <rguenth@gcc.gnu.org>2024-08-22 13:51:32 +0200
commitb07f8a301158e53717b8688cc8ea430b6f02574c (patch)
tree03d0795f8337943ff23722433374b1f0638e929b /gcc
parent4e905bd353fc9f37cd35a7e520cb17f993cbd748 (diff)
downloadgcc-b07f8a301158e53717b8688cc8ea430b6f02574c.zip
gcc-b07f8a301158e53717b8688cc8ea430b6f02574c.tar.gz
gcc-b07f8a301158e53717b8688cc8ea430b6f02574c.tar.bz2
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_apinski@quicinc.com> Co-Authored-By: Richard Biener <rguenther@suse.de>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/fold-const.cc32
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr116454-1.c16
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr116454-2.c12
3 files changed, 50 insertions, 10 deletions
diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 8908e73..ccc499a 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 0000000..6210dcc
--- /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 0000000..a1e1604
--- /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 ();
+}