]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-ssanames, match.pd: get_nonzero_bits/with_*_nonzero_bits* cleanups and improveme...
authorJakub Jelinek <jakub@redhat.com>
Tue, 3 Dec 2024 10:17:49 +0000 (11:17 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 3 Dec 2024 10:17:49 +0000 (11:17 +0100)
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).

2024-12-03  Jakub Jelinek  <jakub@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/match.pd
gcc/testsuite/gcc.dg/tree-ssa/pr117420.c [new file with mode: 0644]
gcc/tree-ssanames.cc
gcc/tree-ssanames.h

index 94202322602c8e86c3213d470ba68f3f4b8db5e3..fd1d8bcc7763fd9fe46a196f57add7069cfa5367 100644 (file)
@@ -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))
-
-/* 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)
+(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
+
+/* 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)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr117420.c b/gcc/testsuite/gcc.dg/tree-ssa/pr117420.c
new file mode 100644 (file)
index 0000000..e423b46
--- /dev/null
@@ -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;
+}
index ae6a0cd48fe66d221b6fe543dc6b8caa3836568a..9f5dd3a5a1906567e41b8c161dd1d2881a5a7fed 100644 (file)
@@ -493,11 +493,11 @@ set_bitmask (tree name, const wide_int &value, const wide_int &mask)
   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.
 
index 731c04f94fd39a2ff603c2c5d145264a7190640e..26a7642f1dc461a999c18f42f1072a17c848cc3a 100644 (file)
@@ -61,6 +61,7 @@ extern bool set_range_info (tree, const vrange &);
 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 *);