On Fri, Jun 12, 2026 at 7:47 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.  For the
> comparison-derived 0/1 masks produced by if-conversion this exposes a plain
> bitwise AND of the original conditions to later passes (replacing a
> COND_EXPR).
>
> 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.

Does this fully fix PR125750; that is the vectorization no longer
causes spills or that part still needs to be resolved?

>
> 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
>         * g++.dg/tree-ssa/mult-negate-zeroone-1.C: New test.
>         * g++.dg/tree-ssa/mult-negate-zeroone-2.C: New test.
> ---
>  gcc/match.pd                                    |  5 +++++
>  .../g++.dg/tree-ssa/mult-negate-zeroone-1.C     | 12 ++++++++++++
>  .../g++.dg/tree-ssa/mult-negate-zeroone-2.C     | 17 +++++++++++++++++
>  3 files changed, 34 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/mult-negate-zeroone-1.C
>  create mode 100644 gcc/testsuite/g++.dg/tree-ssa/mult-negate-zeroone-2.C
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index e0d7ef80e14..1eb36d869aa 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -2518,6 +2518,11 @@ 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:c (negate zero_one_valued_p@0) zero_one_valued_p@1)
> + (negate (bit_and @0 @1)))

So I checked why the above `{ 0 or 1 } * { 0 or 1 }` pattern has the
check for INTEGRAL_TYPE_P and it was just there because originally it
was not using zero_one_valued_p.
The patch looks good to me (Approved).

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/g++.dg/tree-ssa/mult-negate-zeroone-1.C 
> b/gcc/testsuite/g++.dg/tree-ssa/mult-negate-zeroone-1.C
> new file mode 100644
> index 00000000000..002b2d697c5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/tree-ssa/mult-negate-zeroone-1.C
> @@ -0,0 +1,12 @@
> +// Test that { 0, 1 } * -{ 0, 1 } folds to -({ 0, 1 } & { 0, 1 }) and does 
> not
> +// keep a multiply.  Also check the commutative (negated operand first) form.
> +// { 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); }
> +int f4 (int x, int y) { return -(y > 5) * (x > 5); }
> +
> +// { dg-final { scan-tree-dump-not " \* " "optimized" } }
> +// { dg-final { scan-tree-dump-times " & " 4 "optimized" } }
> diff --git a/gcc/testsuite/g++.dg/tree-ssa/mult-negate-zeroone-2.C 
> b/gcc/testsuite/g++.dg/tree-ssa/mult-negate-zeroone-2.C
> new file mode 100644
> index 00000000000..736e664be1f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/tree-ssa/mult-negate-zeroone-2.C
> @@ -0,0 +1,17 @@
> +// Verify { 0, 1 } * -{ 0, 1 } == -({ 0, 1 } & { 0, 1 }) at runtime, 
> including
> +// the commutative (negated operand first) form.
> +// { dg-do run }
> +// { dg-options "-O2" }
> +
> +int __attribute__((noipa)) f (int x, int y) { return (x > 5) * -(y > 5); }
> +int __attribute__((noipa)) g (int x, int y) { return -(y > 5) * (x > 5); }
> +
> +int main () {
> +  for (int x = -3; x < 12; x++)
> +    for (int y = -3; y < 12; y++)
> +      {
> +       if (f (x, y) != -((x > 5) & (y > 5))) __builtin_abort ();
> +       if (g (x, y) != -((x > 5) & (y > 5))) __builtin_abort ();
> +      }
> +  return 0;
> +}
> --
> 2.50.1 (Apple Git-155)
>

Reply via email to