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)