[gcc r17-3460] tree-optimization: Handle variable trip count XOR in final value replacement [PR112104]
Eikansh Gupta via Gcc-cvs <[email protected]>
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:62993cc9d2200ef7a05f317cdef3262996c0ac10 commit r17-3460-g62993cc9d2200ef7a05f317cdef3262996c0ac10 Author: Eikansh Gupta <[email protected]> Date: Thu Jul 23 17:04:17 2026 +0530 tree-optimization: Handle variable trip count XOR in final value replacement [PR112104] 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]> Diff: --- 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(-) 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 000000000000..da05f05962bd --- /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 000000000000..99efd58f1e76 --- /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 69de6b2911ab..4d9ca085127b 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 9e268a1a997e..a3280ba68606 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 cd99cbe86ce5..0466a1d36b60 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));