diff mbox series

match.pd: Optimize a * !a to 0 [PR114009]

Message ID ZegpHD6TdZRk1bDh@tucnak
State New
Headers show
Series match.pd: Optimize a * !a to 0 [PR114009] | expand

Commit Message

Jakub Jelinek March 6, 2024, 8:28 a.m. UTC
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  <jakub@redhat.com>

	PR tree-optimization/114009
	* match.pd (a * !a -> 0): New simplification.

	* gcc.dg/tree-ssa/pr114009.c: New test.


	Jakub

Comments

Richard Biener March 6, 2024, 10:45 a.m. UTC | #1
On Wed, 6 Mar 2024, Jakub Jelinek wrote:

> 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?

OK, though feel free to add ARG_UNUSED to 'captures' as well.
I think the INTEGRAL_TYPE_P should be redundant - the pattern
should work for vectors and complex as well (with integer components
which integer_zerop constrains).

Thanks,
Richard.

> 2024-03-06  Jakub Jelinek  <jakub@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
> 
>
diff mbox series

Patch

--- 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;
+}