https://gcc.gnu.org/g:ad6087410356999730cbe9680ada3077f4afcf76
commit r17-2291-gad6087410356999730cbe9680ada3077f4afcf76 Author: Andrew Pinski <[email protected]> Date: Sat Jul 4 00:32:03 2026 -0700 match: Fix up `((a ^ b) & c) cmp d || a != b` pattern and add support for && case [PR116860] Turns out it was easy to fix these patterns for `--param=logical-op-non-short-circuit=0` case after all. Just add support for `((a ^ b) & c) cmp d && a == b` which is the same as `!(((a ^ b) & c) cmp d || a != b)`. So this adds the bit_and case to support exactly that. Also fixes up some of the `:c` on the operands. `:c` needs to be on the outer bitop and does not need to be on the inner one for bit_xor as it will be the same order as ne/eq. PR tree-optimization/116860 PR tree-optimization/114326 gcc/ChangeLog: * match.pd (`((a ^ b) & c) cmp d || a != b`): Expand to support bit_and and fix up the :c. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/fold-xor-and-or-1.c: New test. * gcc.dg/tree-ssa/fold-xor-or-1.c: New test. * gcc.dg/tree-ssa/pr102793-1.c: Update for the optimization happening in pre. Signed-off-by: Andrew Pinski <[email protected]> Diff: --- gcc/match.pd | 32 ++++++------- gcc/testsuite/gcc.dg/tree-ssa/fold-xor-and-or-1.c | 55 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/fold-xor-or-1.c | 55 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr102793-1.c | 10 +++-- 4 files changed, 134 insertions(+), 18 deletions(-) diff --git a/gcc/match.pd b/gcc/match.pd index a7b658e9e940..cf03333fdc6b 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -3827,35 +3827,37 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (types_match (type, TREE_TYPE (@0))) (bit_xor @0 { build_one_cst (type); } )))))) + /* ((a ^ b) & c) cmp d || a != b --> (0 cmp d || a != b). */ -(for cmp (simple_comparison) +/* ((a ^ b) & c) cmp d && a == b --> (0 cmp d && a == b). */ +(for bitop (bit_ior bit_and) + neeq (ne eq) + (for cmp (simple_comparison) (simplify - (bit_ior + (bitop:c (cmp:c (bit_and:c - (bit_xor:c @0 @1) + (bit_xor @0 @1) tree_expr_nonzero_p@2) @3) - (ne@4 @0 @1)) - (bit_ior + (neeq@4 @0 @1)) + (bitop (cmp { build_zero_cst (TREE_TYPE (@0)); } @3) - @4))) - + @4)) /* (a ^ b) cmp c || a != b --> (0 cmp c || a != b). */ -(for cmp (simple_comparison) +/* (a ^ b) cmp c && a == b --> (0 cmp c || a == b). */ (simplify - (bit_ior + (bitop:c (cmp:c - (bit_xor:c @0 @1) + (bit_xor @0 @1) @2) - (ne@3 @0 @1)) - (bit_ior + (neeq@3 @0 @1)) + (bitop (cmp - { build_zero_cst (TREE_TYPE (@0)); } - @2) - @3))) + { build_zero_cst (TREE_TYPE (@0)); } @2) + @3)))) /* We can't reassociate at all for saturating types. */ (if (!TYPE_SATURATING (type)) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/fold-xor-and-or-1.c b/gcc/testsuite/gcc.dg/tree-ssa/fold-xor-and-or-1.c new file mode 100644 index 000000000000..609532b9599c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/fold-xor-and-or-1.c @@ -0,0 +1,55 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-optimized --param logical-op-non-short-circuit=0" } */ + +typedef unsigned long int uint64_t; + +int cmp1(int d1, int d2) { + if (((d1 ^ d2) & 0xabcd) == 0 || d1 != d2) + return 0; + return 1; +} + +int cmp2(int d1, int d2) { + if (d1 != d2 || ((d1 ^ d2) & 0xabcd) == 0) + return 0; + return 1; +} + +int cmp3(int d1, int d2) { + if (10 > (0xabcd & (d2 ^ d1)) || d2 != d1) + return 0; + return 1; +} + +int cmp4(int d1, int d2) { + if (d2 != d1 || 10 > (0xabcd & (d2 ^ d1))) + return 0; + return 1; +} + +int cmp1_64(uint64_t d1, uint64_t d2) { + if (((d1 ^ d2) & 0xabcd) == 0 || d1 != d2) + return 0; + return 1; +} + +int cmp2_64(uint64_t d1, uint64_t d2) { + if (d1 != d2 || ((d1 ^ d2) & 0xabcd) == 0) + return 0; + return 1; +} + +int cmp3_64(uint64_t d1, uint64_t d2) { + if (10 > (0xabcd & (d2 ^ d1)) || d2 != d1) + return 0; + return 1; +} + +int cmp4_64(uint64_t d1, uint64_t d2) { + if (d2 != d1 || 10 > (0xabcd & (d2 ^ d1))) + return 0; + return 1; +} + +/* The if should be removed, so the condition should not exist */ +/* { dg-final { scan-tree-dump-not "d1_\[0-9\]+.D. \\^ d2_\[0-9\]+.D." "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/fold-xor-or-1.c b/gcc/testsuite/gcc.dg/tree-ssa/fold-xor-or-1.c new file mode 100644 index 000000000000..be66dec523c4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/fold-xor-or-1.c @@ -0,0 +1,55 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-optimized --param logical-op-non-short-circuit=0" } */ + +typedef unsigned long int uint64_t; + +int cmp1(int d1, int d2) { + if ((d1 ^ d2) == 0xabcd || d1 != d2) + return 0; + return 1; +} + +int cmp2(int d1, int d2) { + if (d1 != d2 || (d1 ^ d2) == 0xabcd) + return 0; + return 1; +} + +int cmp3(int d1, int d2) { + if (0xabcd > (d2 ^ d1) || d2 != d1) + return 0; + return 1; +} + +int cmp4(int d1, int d2) { + if (d2 != d1 || 0xabcd > (d2 ^ d1)) + return 0; + return 1; +} + +int cmp1_64(uint64_t d1, uint64_t d2) { + if ((d1 ^ d2) == 0xabcd || d1 != d2) + return 0; + return 1; +} + +int cmp2_64(uint64_t d1, uint64_t d2) { + if (d1 != d2 || (d1 ^ d2) == 0xabcd) + return 0; + return 1; +} + +int cmp3_64(uint64_t d1, uint64_t d2) { + if (0xabcd > (d2 ^ d1) || d2 != d1) + return 0; + return 1; +} + +int cmp4_64(uint64_t d1, uint64_t d2) { + if (d2 != d1 || 0xabcd > (d2 ^ d1)) + return 0; + return 1; +} + +/* The if should be removed, so the condition should not exist */ +/* { dg-final { scan-tree-dump-not "d1_\[0-9\]+.D. \\^ d2_\[0-9\]+.D." "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr102793-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr102793-1.c index 436b4e4bf058..c4c84dcbb467 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr102793-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr102793-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -fdump-tree-pre --param logical-op-non-short-circuit=1" } */ +/* { dg-options "-O3 -fdump-tree-pre -fdump-tree-optimized --param logical-op-non-short-circuit=1" } */ typedef __UINT64_TYPE__ uint64_t; @@ -45,5 +45,9 @@ int noccmp1(uint64_t* s1, uint64_t* s2) return 0; } -/* Check for condition assignments for noccmp0 and noccmp1. */ -/* { dg-final { scan-tree-dump-times {_\d+ = d\d+_\d+ != d\d+_\d+;\n _\d+ = bar_\d+ == 0;} 2 "pre" } } */ +/* Check for condition assignments for noccmp1 and noccmp0. */ +/* { dg-final { scan-tree-dump-times {_\d+ = d\d+_\d+ != d\d+_\d+;\n _\d+ = bar_\d+ == 0;} 1 "pre" } } */ +/* { dg-final { scan-tree-dump-times "optimizing two comparisons " 2 "pre" } } */ +/* The conditional in noccmp1 should be optimized in pre */ +/* { dg-final { scan-tree-dump-times " if " 1 "pre" } } */ +/* { dg-final { scan-tree-dump-times " if " 1 "optimized" } } */
