On Thu, Nov 27, 2025 at 09:02:20PM +0800, Dongyan Chen wrote:
> This patch implements an optimization to transform (a * b) == 0 to
> (a == 0) || (b == 0) for signed and unsigned integer.
Shouldn't that just optimize to (a | b) == 0
instead? At least when a and b have the same type.
> gcc/ChangeLog:
>
> * match.pd: New patterns.
Usually one writes in () what the patterns are (and there is just one
in this case).
> 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)
It should also handle the negation, i.e. also (a * b) != 0 to (a | b) != 0.
And the converts look dangerous to me.
Consider
long long x = 0x7fffffff00000000LL;
int y = 24;
...
return ((int) x) * y == 0;
This is surely true but (x == 0) || (y == 0) is false.
So, you'd need to check that the conversions aren't throwing away any bits.
Plus, blindly comparing TYPE_PRECISION of TREE_TYPE (@2) (which is
INTEGRAL_TYPE_P, so it has meaningful precision) with
the others which aren't verified to be integral at all, could be floating
with completely different meaning of TYPE_PRECISION and issues whether
non-zero floating when converted to integer is converted to 0 or not, or
various other types which might not even have sensible TYPE_PRECISION.
> + (if (!optimize_size
> + && 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; }))))))
> +
Furthermore, tests for generic tree-ssa transformations don't belong
to target specific tests, they should be somewhere in gcc.dg/ or
gcc.dg/tree-ssa/.
Jakub