> On 12 Jun 2026, at 15:59, Andrew Pinski <[email protected]> wrote:
>
>
>
> On Fri, Jun 12, 2026, 5:39 AM <[email protected]> wrote:
> From: Kyrylo Tkachov <[email protected]>
>
> For operands known to be in the range [0, 1], multiplying a 0/1 value by a
> negated 0/1 value is the negation of their bitwise AND:
>
> x * -y == -(x & y) when x, y are in { 0, 1 }.
>
> This complements the existing "{ 0, 1 } * { 0, 1 } -> { 0, 1 } & { 0, 1 }"
> simplification, which does not handle a negated operand. Besides removing the
> multiply, for the comparison-derived 0/1 masks produced by if-conversion this
> exposes a plain bitwise AND of the original conditions to later passes.
>
> This triggers a few times in astcenc in SPEC2026 where it simplifies the
> codegen of one of the hot kernels and gives a ~2.4% improvement on
> aarch64, though the real winners for that kernel are described in
> PR125750. This is just a small cleanup.
>
> Bootstrapped and tested on aarch64-none-linux-gnu.
>
> Signed-off-by: Kyrylo Tkachov <[email protected]>
>
> gcc/ChangeLog:
>
> PR tree-optimization/125750
> * match.pd (mult of a 0/1 value by a negated 0/1 value): New
> simplification.
>
> gcc/testsuite/ChangeLog:
>
> PR tree-optimization/125750
> * gcc.dg/tree-ssa/mult-negate-zeroone-1.c: New test.
> * gcc.dg/tree-ssa/mult-negate-zeroone-2.c: New test.
> ---
> gcc/match.pd | 6 +++++
> .../gcc.dg/tree-ssa/mult-negate-zeroone-1.c | 25 +++++++++++++++++++
> .../gcc.dg/tree-ssa/mult-negate-zeroone-2.c | 19 ++++++++++++++
> 3 files changed, 50 insertions(+)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/mult-negate-zeroone-1.c
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/mult-negate-zeroone-2.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index e0d7ef80e14..bad6d2ec14d 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -2518,6 +2518,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> (if (INTEGRAL_TYPE_P (type))
> (bit_and @0 @1)))
>
> +/* Transform { 0 or 1 } * -{ 0 or 1 } into -({ 0 or 1 } & { 0 or 1 }). */
> +(simplify
> + (mult zero_one_valued_p@0 (negate zero_one_valued_p@1))
>
> `:c` is needed on the mult. Also please reverse the operands. I am trying to
> decide if we need `:s` on the negate.
Ok, I haven’t added it in my revised version but happy to go whatever direction
you recommend.
>
>
> + (if (INTEGRAL_TYPE_P (type))
> + (negate (bit_and @0 @1))))
>
> You dont need INTEGRAL_TYPE_P check here since zero_one_valued_p already has
> that check builtin.
> Also please place this next to the pattern that does `{0 or 1}*{0 or 1}` into
> a bit_and.
Thanks, I’ve sent an updated version.
Kyrill
> Thanks,
> Andrea
>
> +
> /* Fold `(a ? b : 0) | (a ? 0 : c)` into (a ? b : c).
> Handle also ^ and + in replacement of `|`. */
> (for cnd (cond vec_cond)
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/mult-negate-zeroone-1.c
> b/gcc/testsuite/gcc.dg/tree-ssa/mult-negate-zeroone-1.c
> new file mode 100644
> index 00000000000..3c66db986ea
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/mult-negate-zeroone-1.c
> @@ -0,0 +1,25 @@
> +/* Test that { 0, 1 } * -{ 0, 1 } folds to -({ 0, 1 } & { 0, 1 }) and does
> not
> + keep a multiply. */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +
> +int
> +f1 (int x, int y)
> +{
> + return (x > 5) * -(y > 5);
> +}
> +
> +long
> +f2 (long x, long y)
> +{
> + return (long) (x > 5) * -(long) (y > 5);
> +}
> +
> +unsigned
> +f3 (unsigned x, unsigned y)
> +{
> + return (x > 5u) * -(unsigned) (y > 5u);
> +}
> +
> +/* { dg-final { scan-tree-dump-not " \\* " "optimized" } } */
> +/* { dg-final { scan-tree-dump-times " & " 3 "optimized" } } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/mult-negate-zeroone-2.c
> b/gcc/testsuite/gcc.dg/tree-ssa/mult-negate-zeroone-2.c
> new file mode 100644
> index 00000000000..be9ab02e30e
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/mult-negate-zeroone-2.c
> @@ -0,0 +1,19 @@
> +/* Verify { 0, 1 } * -{ 0, 1 } == -({ 0, 1 } & { 0, 1 }) at runtime. */
> +/* { dg-do run } */
> +/* { dg-options "-O2" } */
> +
> +int __attribute__((noipa))
> +f (int x, int y)
> +{
> + return (x > 5) * -(y > 5);
> +}
> +
> +int
> +main (void)
> +{
> + for (int x = -3; x < 12; x++)
> + for (int y = -3; y < 12; y++)
> + if (f (x, y) != -((x > 5) & (y > 5)))
> + __builtin_abort ();
> + return 0;
> +}
> --
> 2.50.1 (Apple Git-155)