在 2025/11/27 21:16, Jakub Jelinek 写道:
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.


Thanks for the review. I think that would be incorrect.

(a | b) == 0 implies both a and b are zero (a==0 && b==0),

but (a * b) == 0 implies that at least one of them is zero.

For example, if a=0 and b=1, a * b is 0, but a | b is 1.

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

I understand the issues you pointed out and the need

for INTEGRAL_TYPE_P checks. I'm working on the fixes now

and will submit a v2 patch once I've verified everything with thorough

testing. It might take a little time to ensure correctness.

Thanks

Dongyan


Reply via email to