analyze_and_compute_bitop_with_inv_effect replaces a loop that repeatedly
applies a bitwise op with a loop-invariant operand by its closed form. The
BIT_XOR case only handled a constant trip count; for a variable count it
bailed out, leaving loops like "for (i=0;i<n;i++) j ^= 1;" in place.
Mask the invariant with that runtime parity to handle a variable count.
A constant count folds as before.
PR tree-optimization/112104
gcc/ChangeLog:
* tree-scalar-evolution.cc (analyze_and_compute_bitop_with_inv_effect):
Handle BIT_XOR_EXPR with a variable trip count.
gcc/testsuite/ChangeLog:
* gcc.target/i386/pr105735-1.c: Bump final value replacement count
from 8 to 9.
* gcc.target/i386/pr105735-3.c: Likewise.
* gcc.dg/tree-ssa/pr112104-1.c: New test.
* gcc.dg/tree-ssa/pr112104-2.c: New test.
Signed-off-by: Eikansh Gupta <[email protected]>
---
gcc/testsuite/gcc.dg/tree-ssa/pr112104-1.c | 45 ++++++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/pr112104-2.c | 60 ++++++++++++++++++++++
gcc/testsuite/gcc.target/i386/pr105735-1.c | 2 +-
gcc/testsuite/gcc.target/i386/pr105735-3.c | 2 +-
gcc/tree-scalar-evolution.cc | 16 +++---
5 files changed, 117 insertions(+), 8 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr112104-1.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr112104-2.c
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr112104-1.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr112104-1.c
new file mode 100644
index 00000000000..da05f05962b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr112104-1.c
@@ -0,0 +1,45 @@
+/* PR tree-optimization/112104 */
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-sccp-details" } */
+
+unsigned int
+__attribute__ ((noipa))
+f_xor (unsigned int tmp, int n, unsigned int inv)
+{
+ unsigned int r = tmp;
+ for (int i = 0; i < n; i++)
+ r ^= inv;
+ return r;
+}
+
+int
+__attribute__ ((noipa))
+f_xor1 (int n)
+{
+ int j = 0;
+ for (int i = 0; i < n; i++)
+ j ^= 1;
+ return j;
+}
+
+unsigned long long
+__attribute__ ((noipa))
+f_xor64 (unsigned long long tmp, long n, unsigned long long inv)
+{
+ unsigned long long r = tmp;
+ for (long i = 0; i < n; i++)
+ r ^= inv;
+ return r;
+}
+
+unsigned int
+__attribute__ ((noipa))
+f_xorc (unsigned int tmp, int n)
+{
+ unsigned int r = tmp;
+ for (int i = 0; i < n; i++)
+ r ^= 11304;
+ return r;
+}
+
+/* { dg-final { scan-tree-dump-times {final value replacement} 4 "sccp" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr112104-2.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr112104-2.c
new file mode 100644
index 00000000000..99efd58f1e7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr112104-2.c
@@ -0,0 +1,60 @@
+/* PR tree-optimization/112104 */
+/* { dg-do run } */
+/* { dg-options "-O1" } */
+
+#include "pr112104-1.c"
+
+int
+main (void)
+{
+ unsigned int tmp = 0x1101;
+ unsigned int inv = 0x111101;
+ unsigned long long tmp64 = 0x1101ULL;
+ unsigned long long inv64 = 0xdeadbeefcafebabeULL;
+
+ if (f_xor (tmp, 64, inv) != 0x1101)
+ __builtin_abort ();
+ if (f_xor (tmp, 63, inv) != 0x110000)
+ __builtin_abort ();
+
+ if (f_xor (tmp, 1, inv) != 0x110000)
+ __builtin_abort ();
+ if (f_xor (tmp, 2, inv) != 0x1101)
+ __builtin_abort ();
+
+ if (f_xor1 (64) != 0)
+ __builtin_abort ();
+ if (f_xor1 (63) != 1)
+ __builtin_abort ();
+ if (f_xor1 (1) != 1)
+ __builtin_abort ();
+ if (f_xor1 (2) != 0)
+ __builtin_abort ();
+
+ if (f_xor64 (tmp64, 64, inv64) != 0x1101ULL)
+ __builtin_abort ();
+ if (f_xor64 (tmp64, 63, inv64) != 0xdeadbeefcafeabbfULL)
+ __builtin_abort ();
+ if (f_xor64 (tmp64, 1, inv64) != 0xdeadbeefcafeabbfULL)
+ __builtin_abort ();
+ if (f_xor64 (tmp64, 2, inv64) != 0x1101ULL)
+ __builtin_abort ();
+
+ if (f_xorc (tmp, 64) != 0x1101)
+ __builtin_abort ();
+ if (f_xorc (tmp, 63) != 0x3d29)
+ __builtin_abort ();
+ if (f_xorc (tmp, 1) != 0x3d29)
+ __builtin_abort ();
+ if (f_xorc (tmp, 2) != 0x1101)
+ __builtin_abort ();
+
+ if (f_xor (tmp, 0, inv) != 0x1101)
+ __builtin_abort ();
+ if (f_xor (tmp, -5, inv) != 0x1101)
+ __builtin_abort ();
+ if (f_xor1 (0) != 0)
+ __builtin_abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr105735-1.c
b/gcc/testsuite/gcc.target/i386/pr105735-1.c
index 69de6b2911a..4d9ca085127 100644
--- a/gcc/testsuite/gcc.target/i386/pr105735-1.c
+++ b/gcc/testsuite/gcc.target/i386/pr105735-1.c
@@ -1,6 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-sccp-details" } */
-/* { dg-final { scan-tree-dump-times {final value replacement} 8 "sccp" } } */
+/* { dg-final { scan-tree-dump-times {final value replacement} 9 "sccp" } } */
unsigned int
__attribute__((noipa))
diff --git a/gcc/testsuite/gcc.target/i386/pr105735-3.c
b/gcc/testsuite/gcc.target/i386/pr105735-3.c
index 9e268a1a997..a3280ba6860 100644
--- a/gcc/testsuite/gcc.target/i386/pr105735-3.c
+++ b/gcc/testsuite/gcc.target/i386/pr105735-3.c
@@ -1,6 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-sccp-details" } */
-/* { dg-final { scan-tree-dump-times {final value replacement} 8 "sccp" } } */
+/* { dg-final { scan-tree-dump-times {final value replacement} 9 "sccp" } } */
unsigned int
__attribute__((noipa))
diff --git a/gcc/tree-scalar-evolution.cc b/gcc/tree-scalar-evolution.cc
index cd99cbe86ce..0466a1d36b6 100644
--- a/gcc/tree-scalar-evolution.cc
+++ b/gcc/tree-scalar-evolution.cc
@@ -3850,12 +3850,16 @@ analyze_and_compute_bitop_with_inv_effect (class loop*
loop, tree phidef,
if (code1 == BIT_XOR_EXPR)
{
- if (!tree_fits_uhwi_p (niter))
- return NULL_TREE;
- unsigned HOST_WIDE_INT niter_num;
- niter_num = tree_to_uhwi (niter);
- if (niter_num % 2 != 0)
- match_op[0] = build_zero_cst (type);
+ tree niter_type = TREE_TYPE (niter);
+ tree one = build_one_cst (niter_type);
+ tree contributes = fold_build2 (BIT_XOR_EXPR, niter_type,
+ fold_build2 (BIT_AND_EXPR, niter_type,
+ niter, one),
+ one);
+ /* mask is all-ones when the invariant contributes, zero otherwise. */
+ tree mask = fold_build1 (NEGATE_EXPR, type,
+ fold_convert (type, contributes));
+ match_op[0] = fold_build2 (BIT_AND_EXPR, type, match_op[0], mask);
}
inv = PHI_ARG_DEF_FROM_EDGE (header_phi, loop_preheader_edge (loop));
--
2.34.1