From: Daniel Barboza Date: Fri, 28 Nov 2025 01:03:18 +0000 (-0300) Subject: match.pd: x&c ?(x op c):(x|c) -> x^c [PR122615, PR122616] X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=73824bffde7a2226a864313546f8f0bd127a22b7;p=thirdparty%2Fgcc.git match.pd: x&c ?(x op c):(x|c) -> x^c [PR122615, PR122616] Add a single pattern to reduce these patterns to "x ^ c": x & c ? (x - c) | (x | c) x & c ? (x & ~c) | (x | c) As long as "c" has a single bit set. PR tree-optimization/122615 PR tree-optimization/122616 gcc/ChangeLog: * match.pd (`x & c ? (x - c) | (x | c)`): New pattern. (`x & c ? (x & ~c) | (x | c)`): Likewise. gcc/testsuite/ChangeLog: * gcc.dg/torture/pr122615.c: New test. * gcc.dg/torture/pr122616.c: Likewise. Co-authored-by: Jeff Law Signed-off-by: Daniel Barboza --- diff --git a/gcc/match.pd b/gcc/match.pd index f164ec59100..bf410a75f5f 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -6617,6 +6617,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (convert (minus { arg; } (convert:type1 @0)))))))))) #endif +/* X & C1 ? (X + -C1) : (X | C1) -> X ^ C1 + X & C1 ? (X & ~C1) : (X | C1) -> X ^ C1 + when C1 has a single bit set. */ +(for op (plus bit_and) + (simplify + (cond (ne (bit_and @0 INTEGER_CST@1) integer_zerop) + (op @0 INTEGER_CST@2) (bit_ior @0 @1)) + (with { + auto c1 = wi::to_wide (@1); + auto c2 = wi::to_wide (@2); + } + (if (wi::popcount (c1) == 1 + && ((op == PLUS_EXPR && wi::eq_p (wi::neg (c2), c1)) + || (op == BIT_AND_EXPR && wi::eq_p (wi::bit_not (c2), c1)))) + (bit_xor @0 @1))))) + (simplify (convert (cond@0 @1 INTEGER_CST@2 INTEGER_CST@3)) (if (INTEGRAL_TYPE_P (type) diff --git a/gcc/testsuite/gcc.dg/torture/pr122615.c b/gcc/testsuite/gcc.dg/torture/pr122615.c new file mode 100644 index 00000000000..9f4f3c49a01 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr122615.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-fdump-tree-original" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */ + +int f1 (int x) +{ + return x & 1 ? (x & ~1) : (x | 1); +} + +int f2 (int x) +{ + return x & 2 ? (x & ~2) : (x | 2); +} + +int f3 (int x) +{ + return x & 3 ? (x & ~3) : (x | 3); +} + +/* { dg-final { scan-tree-dump-times "x \\^ 1" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "x \\^ 2" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "x \\^ 3" 0 "original" } } */ diff --git a/gcc/testsuite/gcc.dg/torture/pr122616.c b/gcc/testsuite/gcc.dg/torture/pr122616.c new file mode 100644 index 00000000000..77d364ef2f4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr122616.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-fdump-tree-original" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */ + +int f1 (int x) +{ + return x & 1 ? (x - 1) : (x | 1); +} + +int f2 (int x) +{ + return x & 2 ? (x - 2) : (x | 2); +} + +int f3 (int x) +{ + return x & 3 ? (x - 3) : (x | 3); +} + +/* { dg-final { scan-tree-dump-times "x \\^ 1" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "x \\^ 2" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "x \\^ 3" 0 "original" } } */