On Tue, 26 Nov 2024, Jakub Jelinek wrote:

> Hi!
> 
> The following patch implements the with_*_nonzero_bits* cleanups and
> improvements I was talking about.
> 
> get_nonzero_bits is extended to also handle BIT_AND_EXPR (as a tree or
> as SSA_NAME with BIT_AND_EXPR def_stmt), new function is added for the
> bits known to be set (get_known_nonzero_bits) and the match.pd predicates
> are renamed and adjusted, so that there is no confusion on which one to
> use (one is named and documented to be internal), changed so that it can be
> used only as a simple predicate, not match some operands, and that it doesn't
> try to match twice for the GIMPLE case (where SSA_NAME with integral or 
> pointer
> type matches, but SSA_NAME with BIT_AND_EXPR def_stmt matched differently).
> Furthermore, get_nonzero_bits just returns the all bits set (or
> get_known_nonzero_bits no bits set) fallback if the argument isn't a
> SSA_NAME (nor INTEGER_CST or whatever the functions handle explicitly).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

I've pondered a while about that we now have get_nonzero_bits
and get_known_nonzero_bits where it's only obvious what the difference
is when you know what get_nonzero_bits did.  I realize a mass rename
would cover also RTL and value-range, so I don't think we need this
now.  But it will be surely a source of confusion for newcomers?

Thanks,
Richard.

> 2024-11-26  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR tree-optimization/117420
>       * tree-ssanames.h (get_known_nonzero_bits): Declare.
>       * tree-ssanames.cc (get_nonzero_bits): New wrapper function.  Move old
>       definition to ...
>       (get_nonzero_bits_1): ... here, add static.  Change widest_int in
>       function comment to wide_int.
>       (get_known_nonzero_bits_1, get_known_nonzero_bits): New functions.
>       * match.pd (with_possible_nonzero_bits2): Rename to ...
>       (with_possible_nonzero_bits): ... this.  Guard the bit_and case with
>       #if GENERIC.  Change to a normal match predicate without parameters.
>       Rename the old with_possible_nonzero_bits match to ...
>       (with_possible_nonzero_bits_1): ... this.
>       (with_certain_nonzero_bits2): Remove.
>       (with_known_nonzero_bits_1, with_known_nonzero_bits): New match
>       predicates.
>       (X == C (or X & Z == Y | C) is impossible if ~nonzero(X) & C != 0):
>       Use with_known_nonzero_bits@0 instead of
>       (with_certain_nonzero_bits2 @1), use with_possible_nonzero_bits@0
>       instead of (with_possible_nonzero_bits2 @0) and
>       get_known_nonzero_bits (@1) instead of wi::to_wide (@1).
> 
>       * gcc.dg/tree-ssa/pr117420.c: New test.
> 
> --- gcc/tree-ssanames.h.jj    2024-07-01 11:28:23.461228272 +0200
> +++ gcc/tree-ssanames.h       2024-11-25 11:11:48.598982744 +0100
> @@ -61,6 +61,7 @@ extern bool set_range_info (tree, const
>  extern void set_nonzero_bits (tree, const wide_int &);
>  extern void set_bitmask (tree, const wide_int &value, const wide_int &mask);
>  extern wide_int get_nonzero_bits (const_tree);
> +extern wide_int get_known_nonzero_bits (const_tree);
>  extern bool ssa_name_has_boolean_range (tree);
>  extern void init_ssanames (struct function *, int);
>  extern void fini_ssanames (struct function *);
> --- gcc/tree-ssanames.cc.jj   2024-11-23 13:00:31.536981942 +0100
> +++ gcc/tree-ssanames.cc      2024-11-26 08:53:58.536649673 +0100
> @@ -493,11 +493,11 @@ set_bitmask (tree name, const wide_int &
>    set_range_info (name, r);
>  }
>  
> -/* Return a widest_int with potentially non-zero bits in SSA_NAME
> +/* Return a wide_int with potentially non-zero bits in SSA_NAME
>     NAME, the constant for INTEGER_CST, or -1 if unknown.  */
>  
> -wide_int
> -get_nonzero_bits (const_tree name)
> +static wide_int
> +get_nonzero_bits_1 (const_tree name)
>  {
>    if (TREE_CODE (name) == INTEGER_CST)
>      return wi::to_wide (name);
> @@ -508,6 +508,9 @@ get_nonzero_bits (const_tree name)
>    /* Use element_precision instead of TYPE_PRECISION so complex and
>       vector types get a non-zero precision.  */
>    unsigned int precision = element_precision (TREE_TYPE (name));
> +  if (TREE_CODE (name) != SSA_NAME)
> +    return wi::shwi (-1, precision);
> +
>    if (POINTER_TYPE_P (TREE_TYPE (name)))
>      {
>        struct ptr_info_def *pi = SSA_NAME_PTR_INFO (name);
> @@ -525,6 +528,81 @@ get_nonzero_bits (const_tree name)
>    return tmp.get_nonzero_bits ();
>  }
>  
> +/* Return a wide_int with potentially non-zero bits in SSA_NAME
> +   NAME, the constant for INTEGER_CST, or -1 if unknown.
> +   In addition to what get_nonzero_bits_1 handles, this handles one
> +   level of BIT_AND_EXPR, either as a def_stmt or tree directly.  */
> +
> +wide_int
> +get_nonzero_bits (const_tree name)
> +{
> +  if (TREE_CODE (name) == BIT_AND_EXPR)
> +    return (get_nonzero_bits_1 (TREE_OPERAND (name, 0))
> +         & get_nonzero_bits_1 (TREE_OPERAND (name, 1)));
> +  if (TREE_CODE (name) == SSA_NAME)
> +    {
> +      gimple *g = SSA_NAME_DEF_STMT (name);
> +      if (g
> +       && is_gimple_assign (g)
> +       && gimple_assign_rhs_code (g) == BIT_AND_EXPR)
> +     return (get_nonzero_bits_1 (name)
> +             & get_nonzero_bits_1 (gimple_assign_rhs1 (g))
> +             & get_nonzero_bits_1 (gimple_assign_rhs2 (g)));
> +    }
> +  return get_nonzero_bits_1 (name);
> +}
> +
> +/* Return a wide_int with known non-zero bits in SSA_NAME
> +   NAME (bits whose values aren't known are also clear), the constant
> +   for INTEGER_CST, or 0 if unknown.  */
> +
> +static wide_int
> +get_known_nonzero_bits_1 (const_tree name)
> +{
> +  if (TREE_CODE (name) == INTEGER_CST)
> +    return wi::to_wide (name);
> +
> +  /* Use element_precision instead of TYPE_PRECISION so complex and
> +     vector types get a non-zero precision.  */
> +  unsigned int precision = element_precision (TREE_TYPE (name));
> +  if (TREE_CODE (name) != SSA_NAME || POINTER_TYPE_P (TREE_TYPE (name)))
> +    return wi::shwi (0, precision);
> +
> +  if (!range_info_p (name) || !irange::supports_p (TREE_TYPE (name)))
> +    return wi::shwi (0, precision);
> +
> +  int_range_max tmp;
> +  range_info_get_range (name, tmp);
> +  if (tmp.undefined_p ())
> +    return wi::shwi (0, precision);
> +  irange_bitmask bm = tmp.get_bitmask ();
> +  return bm.value () & ~bm.mask ();
> +}
> +
> +/* Return a wide_int with known non-zero bits in SSA_NAME
> +   NAME, the constant for INTEGER_CST, or -1 if unknown.
> +   In addition to what get_known_nonzero_bits_1 handles, this handles one
> +   level of BIT_IOR_EXPR, either as a def_stmt or tree directly.  */
> +
> +wide_int
> +get_known_nonzero_bits (const_tree name)
> +{
> +  if (TREE_CODE (name) == BIT_IOR_EXPR)
> +    return (get_known_nonzero_bits_1 (TREE_OPERAND (name, 0))
> +         | get_known_nonzero_bits_1 (TREE_OPERAND (name, 1)));
> +  if (TREE_CODE (name) == SSA_NAME)
> +    {
> +      gimple *g = SSA_NAME_DEF_STMT (name);
> +      if (g
> +       && is_gimple_assign (g)
> +       && gimple_assign_rhs_code (g) == BIT_IOR_EXPR)
> +     return (get_known_nonzero_bits_1 (name)
> +             | get_known_nonzero_bits_1 (gimple_assign_rhs1 (g))
> +             | get_known_nonzero_bits_1 (gimple_assign_rhs2 (g)));
> +    }
> +  return get_known_nonzero_bits_1 (name);
> +}
> +
>  /* Return TRUE is OP, an SSA_NAME has a range of values [0..1], false
>     otherwise.
>  
> --- gcc/match.pd.jj   2024-11-22 19:50:15.389344167 +0100
> +++ gcc/match.pd      2024-11-25 13:08:06.430386845 +0100
> @@ -2869,32 +2869,45 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>       { constant_boolean_node (cmp == LT_EXPR, type); })))))
>  
>  /* Arguments on which one can call get_nonzero_bits to get the bits
> -   possibly set.  */
> -(match with_possible_nonzero_bits
> +   possibly set.  with_possible_nonzero_bits_1 is an internal version,
> +   use with_possible_nonzero_bits.  */
> +(match with_possible_nonzero_bits_1
>   INTEGER_CST@0)
> -(match with_possible_nonzero_bits
> +(match with_possible_nonzero_bits_1
>   POLY_INT_CST@0)
> -(match with_possible_nonzero_bits
> +(match with_possible_nonzero_bits_1
>   SSA_NAME@0
>   (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) || POINTER_TYPE_P (TREE_TYPE (@0)))))
>  /* Slightly extended version, do not make it recursive to keep it cheap.  */
> -(match (with_possible_nonzero_bits2 @0)
> - with_possible_nonzero_bits@0)
> -(match (with_possible_nonzero_bits2 @0)
> - (bit_and:c with_possible_nonzero_bits@0 @2))
> +(match with_possible_nonzero_bits
> + with_possible_nonzero_bits_1@0)
> +#if GENERIC
> +(match with_possible_nonzero_bits
> + (bit_and:c with_possible_nonzero_bits_1@0 @1))
> +#endif
>  
> -/* Same for bits that are known to be set, but we do not have
> -   an equivalent to get_nonzero_bits yet.  */
> -(match (with_certain_nonzero_bits2 @0)
> +/* Arguments on which one can call get_known_nonzero_bits to get the
> +   bits known to be set.  with_known_nonzero_bits_1 is an internal version,
> +   use with_known_nonzero_bits.  */
> +(match with_known_nonzero_bits_1
>   INTEGER_CST@0)
> -(match (with_certain_nonzero_bits2 @0)
> - (bit_ior @1 INTEGER_CST@0))
> +(match with_known_nonzero_bits_1
> + SSA_NAME@0
> + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))))
> +/* Slightly extended version, do not make it recursive to keep it cheap.  */
> +(match with_known_nonzero_bits
> + with_known_nonzero_bits_1@0)
> +#if GENERIC
> +(match with_known_nonzero_bits
> + (bit_ior:c with_known_nonzero_bits_1@0 @1))
> +#endif
>  
>  /* X == C (or X & Z == Y | C) is impossible if ~nonzero(X) & C != 0.  */
>  (for cmp (eq ne)
>   (simplify
> -  (cmp:c (with_possible_nonzero_bits2 @0) (with_certain_nonzero_bits2 @1))
> -  (if (wi::bit_and_not (wi::to_wide (@1), get_nonzero_bits (@0)) != 0)
> +  (cmp:c with_possible_nonzero_bits@0 with_known_nonzero_bits@1)
> +  (if (wi::bit_and_not (get_known_nonzero_bits (@1),
> +                     get_nonzero_bits (@0)) != 0)
>     { constant_boolean_node (cmp == NE_EXPR, type); })))
>  
>  /* ((X inner_op C0) outer_op C1)
> --- gcc/testsuite/gcc.dg/tree-ssa/pr117420.c.jj       2024-11-25 
> 12:52:41.090468349 +0100
> +++ gcc/testsuite/gcc.dg/tree-ssa/pr117420.c  2024-11-25 12:53:40.308631183 
> +0100
> @@ -0,0 +1,16 @@
> +/* PR tree-optimization/117420 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump "return 0;" "optimized" } } */
> +
> +int
> +foo (unsigned long x, unsigned long y)
> +{
> +  x |= 0x11000L;
> +  x &= ~0xfffL;
> +  x += 42L;
> +  y &= ~0x10ffL;
> +  y |= 0x100L;
> +  y += 21L;
> +  return x == y;
> +}
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to