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
>

Reply via email to