diff options
author | Andrew Pinski <quic_apinski@quicinc.com> | 2024-08-21 17:41:38 -0700 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2024-08-22 13:51:32 +0200 |
commit | b07f8a301158e53717b8688cc8ea430b6f02574c (patch) | |
tree | 03d0795f8337943ff23722433374b1f0638e929b /gcc | |
parent | 4e905bd353fc9f37cd35a7e520cb17f993cbd748 (diff) | |
download | gcc-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.cc | 32 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/pr116454-1.c | 16 | ||||
-rw-r--r-- | 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 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 (); +} |