On Thu, Nov 27, 2025 at 5:04 AM Dongyan Chen <[email protected]> wrote: > > This patch implements an optimization to transform (a * b) == 0 to > (a == 0) || (b == 0) for signed and unsigned integer. > > gcc/ChangeLog: > > * match.pd: New patterns. > > gcc/testsuite/ChangeLog: > > * gcc.target/riscv/mul-eq-zero-1.c: New test. > * gcc.target/riscv/mul-eq-zero-2.c: New test. > --- > gcc/match.pd | 15 +++++++++++++++ > gcc/testsuite/gcc.target/riscv/mul-eq-zero-1.c | 17 +++++++++++++++++ > gcc/testsuite/gcc.target/riscv/mul-eq-zero-2.c | 12 ++++++++++++ > 3 files changed, 44 insertions(+) > create mode 100644 gcc/testsuite/gcc.target/riscv/mul-eq-zero-1.c > create mode 100644 gcc/testsuite/gcc.target/riscv/mul-eq-zero-2.c > > diff --git a/gcc/match.pd b/gcc/match.pd > index 05c8b59eb9e..0ed297f90f9 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -320,6 +320,21 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > @0))) > #endif > > +/* Fold (a * b == 0) to (a == 0) || (b == 0) for signed and unsigned integer > */ > +(simplify > + (eq (mult (convert?@2 @0) (convert?@3 @1)) integer_zerop) > + (if (!optimize_size
Why not optimize_size? We don't have any patterns in match.pd that depend on optimizing for size currently. Could this instead be done in isel/expand? And convert `(a == 0) || (b == 0)` into `(a*b == 0)` on the gimple level and then doing the opposite in isel/expand and depending on the cost there? Also I see you don't handle `a*b != 0` which is `a != 0 && b != 0`. I posted a limited form of the `!= 0` case before: https://gcc.gnu.org/pipermail/gcc-patches/2023-September/630651.html And it was rejected because the a*b !=/== 0 is simpler than the other form. This is why I asked about doing this in isel/expand instead. Thanks, Andrew > + && INTEGRAL_TYPE_P (TREE_TYPE (@2))) > + (with { > + tree zero0 = build_zero_cst (TREE_TYPE (@0)); > + tree zero1 = build_zero_cst (TREE_TYPE (@1)); > + } > + (if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@2)) > + || (TYPE_PRECISION (TREE_TYPE (@2)) >= TYPE_PRECISION (TREE_TYPE > (@0)) > + + TYPE_PRECISION (TREE_TYPE > (@1)))) > + (bit_ior (eq @0 { zero0; }) > + (eq @1 { zero1; })))))) > + > /* -x == x -> x == 0 */ > (for cmp (eq ne) > (simplify > diff --git a/gcc/testsuite/gcc.target/riscv/mul-eq-zero-1.c > b/gcc/testsuite/gcc.target/riscv/mul-eq-zero-1.c > new file mode 100644 > index 00000000000..4af602bfa9e > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/mul-eq-zero-1.c > @@ -0,0 +1,17 @@ > +/* { dg-do compile } */ > +/* { dg-options "-march=rv64gc -mabi=lp64" { target { rv64} } } */ > +/* { dg-skip-if "" { *-*-* } { "-Oz" } } */ > + > +#include <stdbool.h> > +#include <stdint.h> > + > +bool foo(int32_t a, int32_t b) { > + return ((int32_t)a * b) == 0; > +} > + > +bool foo2(uint8_t a, uint8_t b) { > + return ((uint32_t)a * b) == 0; > +} > + > +/* { dg-final { scan-assembler-times {seqz} } } */ > +/* { dg-final { scan-assembler-not {mulw} } } */ > diff --git a/gcc/testsuite/gcc.target/riscv/mul-eq-zero-2.c > b/gcc/testsuite/gcc.target/riscv/mul-eq-zero-2.c > new file mode 100644 > index 00000000000..e8a406e6519 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/mul-eq-zero-2.c > @@ -0,0 +1,12 @@ > +/* { dg-do compile } */ > +/* { dg-options "-march=rv64gc -mabi=lp64" { target { rv64} } } */ > +/* { dg-skip-if "" { *-*-* } { "-Oz" } } */ > + > +#include <stdbool.h> > +#include <stdint.h> > + > +bool foo(uint32_t a, uint32_t b) { > + return ((uint32_t)a * b) == 0; > +} > + > +/* { dg-final { scan-assembler-times {mulw} } } */ > -- > 2.43.0 >
