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
>

Reply via email to