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

Reply via email to