On Tue, Aug 11, 2026 at 11:43 AM Eikansh Gupta <[email protected]> wrote: > > 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.
OK. Thanks, Richard. > 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 >
