On 11/28/25 1:10 AM, Dongyan Chen wrote:
在 2025/11/28 12:41, Andrew Pinski 写道:
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
Thanks for the review and explanation. My primary motivation for this
patch is to address a code generation discrepancy between LLVM and GCC
on RISC-V (https://godbolt.org/z/5b81vbEEa). In certain scenarios (e.g.,
at -O3), splitting the multiplication into checks proves to be more
performant on RISC-V hardware, and I plan to address the `!= 0` case as
well.
I agree that `match.pd` is not the right place for this if it conflicts
with the GIMPLE canonical form and lacks cost awareness.
Could you advise on the preferred approach?
Should I implement this transformation in the RISC-V backend (e.g.,
using define_split or generic expansion in `riscv.md`) to avoid
affecting other targets?Or would you prefer a generic handling in isel /
expand that queries the target costs?
I'm leaning towards handling it in the RISC-V backend to be safe and
target-specific, and I'd appreciate your guidance.I don't think a define_split will do what you want here. The core issue
is you need a 2 -> N split where N > 2. That's just not going to work.
I'd be looking at something expand-time or gimple. As noted here the
question for gimple is costing/canonicalization. For expansion the
question is going to be finding a good place to adjust the generated
code that isn't horribly special cased.
Jeff