On Thu, Nov 27, 2025 at 12:26 PM Daniel Barboza
<[email protected]> wrote:
>
> 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 122615
>         PR 122616
>
> gcc/ChangeLog:
>
>         * match.pd: New pattern.

The changelog might be better this way:
 * match.pd (`x & c ? (x - c) | (x | c)`): New pattern.
(`x & c ? (x & ~c) | (x | c)`): Likewise.
So it might be easier to see what the change did.

>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/torture/pr122615.c: New test.
>         * gcc.dg/torture/pr122616.c: New test.

First, LGTM with some minor changes listed below (but I can't approve it).

>
> Co-authored-by: Jeff Law <[email protected]>
> Signed-off-by: Daniel Barboza <[email protected]>
> ---
>  gcc/match.pd                            | 15 +++++++++++++++
>  gcc/testsuite/gcc.dg/torture/pr122615.c | 22 ++++++++++++++++++++++
>  gcc/testsuite/gcc.dg/torture/pr122616.c | 22 ++++++++++++++++++++++
>  3 files changed, 59 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.dg/torture/pr122615.c
>  create mode 100644 gcc/testsuite/gcc.dg/torture/pr122616.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index 05c8b59eb9e..fbef7fd6e0f 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -6627,6 +6627,21 @@ 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 INTEGER_CST@1))

The second `INTEGER_CST@1` should/needs to just be `@1`. I am actually
surprised that `INTEGER_CST@1` twice worked. But maybe genmatch does
not check.

> +    (with {
> +      auto c1 = wi::to_wide (@1);
> +      auto c2 = wi::to_wide (@2); }

I think the style in the file is:
    (with { auto c1 = wi::to_wide (@1);
               auto c2 = wi::to_wide (@2); }
Or
  (with {
    auto c1 = wi::to_wide (@1);
    auto c2 = wi::to_wide (@2);
   }
Both of these are used in the file but I didn't see one or the other
as the dominating one for 2 lines.
There is one which is like the format you did but the first line is a comment.
I am ok with both of the later formats as those are what is already in use.

Thanks,
Andrew Pinski

> +     (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" } } */
> --
> 2.43.0
>

Reply via email to