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) >
