Hi! The following patch attempts to fix an optimization regression through adding a simple simplification. We already have the /* (m1 CMP m2) * d -> (m1 CMP m2) ? d : 0 */ (if (!canonicalize_math_p ()) (for cmp (tcc_comparison) (simplify (mult:c (convert (cmp@0 @1 @2)) @3) (if (INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (TREE_TYPE (@0))) (cond @0 @3 { build_zero_cst (type); }))) optimization which otherwise triggers during the a * !a multiplication, but that is done only late and we aren't able through range assumptions optimize it yet anyway.
The patch adds a specific simplification for it. If a is zero, then a * !a will be 0 * 1 (or for signed 1-bit 0 * -1) and so 0. If a is non-zero, then a * !a will be a * 0 and so again 0. I had to use a hack, TREE_TYPE (@0) in the condition as opposed to using just type, because otherwise I get a false positive warning. The captures parameter is marked ARG_UNUSED in gimple, but not in generic and we end up with tree generic_simplify_168 (location_t ARG_UNUSED (loc), const tree ARG_UNUSED (type), tree ARG_UNUSED (_p0), tree ARG_UNUSED (_p1), tree *captures) { const bool debug_dump = dump_file && (dump_flags & TDF_FOLDING); if (INTEGRAL_TYPE_P (type) ) { if (TREE_SIDE_EFFECTS (_p1)) goto next_after_fail309; if (UNLIKELY (!dbg_cnt (match))) goto next_after_fail309; { tree _r; _r = build_zero_cst (type); if (UNLIKELY (debug_dump)) generic_dump_logs ("match.pd", 216, __FILE__, __LINE__, true); return _r; } next_after_fail309:; } return NULL_TREE; } there. I've looked at similar cases and in (simplify (mod @0 integer_onep) { build_zero_cst (type); }) case we don't get captures unused because it is used a single time and therefore evaluate it for side-effects instead of punting on them, and in (pointer_diff @@0 @0) { build_zero_cst (type); }) we do so as well. Though, using @@0 instead of @0 on either operand of this simplification doesn't help. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2024-03-06 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/114009 * match.pd (a * !a -> 0): New simplification. * gcc.dg/tree-ssa/pr114009.c: New test. --- gcc/match.pd.jj 2024-03-01 14:56:42.442810053 +0100 +++ gcc/match.pd 2024-03-05 22:53:25.202579435 +0100 @@ -1219,6 +1219,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) && tree_nop_conversion_p (type, TREE_TYPE (@1))) (lshift @0 @2))) +/* Fold a * !a into 0. */ +(simplify + (mult:c @0 (convert? (eq @0 integer_zerop))) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))) + { build_zero_cst (type); })) + /* Shifts by precision or greater result in zero. */ (for shift (lshift rshift) (simplify --- gcc/testsuite/gcc.dg/tree-ssa/pr114009.c.jj 2024-03-05 15:18:41.274541636 +0100 +++ gcc/testsuite/gcc.dg/tree-ssa/pr114009.c 2024-03-05 15:16:09.056589675 +0100 @@ -0,0 +1,24 @@ +/* PR tree-optimization/114009 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times " return 0;" 3 "optimized" } } */ + +int +foo (int x) +{ + x = (x / 2) * 2; + return (!x) * x; +} + +int +bar (int x, int y) +{ + (void) x; + return y * !y; +} + +unsigned long long +baz (unsigned long long x) +{ + return (!x) * x; +} Jakub