https://gcc.gnu.org/g:63a8128218cc421b4294f9b8b139197a985ce375

commit r16-1199-g63a8128218cc421b4294f9b8b139197a985ce375
Author: Richard Biener <rguent...@suse.de>
Date:   Wed May 28 14:13:00 2025 +0200

    Refactor CTZ detection in forwprop
    
    The following refactors the CTZ detection code to be more easily
    extensible to also handle CLZ.
    
            * tree-ssa-forwprop.cc (optimize_count_trailing_zeroes):
            Inline into ...
            (simplify_count_trailing_zeroes): ... this function.
            Split out ...
            (check_ctz_table): ... a wrapper for CONSTRUCTOR vs. STRING_CST
            handling.

Diff:
---
 gcc/tree-ssa-forwprop.cc | 161 ++++++++++++++++++++++-------------------------
 1 file changed, 74 insertions(+), 87 deletions(-)

diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
index 27197bbc0769..4ef75ba98bd1 100644
--- a/gcc/tree-ssa-forwprop.cc
+++ b/gcc/tree-ssa-forwprop.cc
@@ -2592,6 +2592,22 @@ check_ctz_string (tree string, unsigned HOST_WIDE_INT 
mulc,
   return matched == bits;
 }
 
+/* Check whether CTOR contains a valid ctz table.  */
+static bool
+check_ctz_table (tree ctor, tree type, unsigned HOST_WIDE_INT mulc,
+                HOST_WIDE_INT &zero_val, unsigned shift, unsigned bits)
+{
+  if (TREE_CODE (ctor) == CONSTRUCTOR)
+    return check_ctz_array (ctor, mulc, zero_val, shift, bits);
+  else if (TREE_CODE (ctor) == STRING_CST
+          && TYPE_PRECISION (type) == CHAR_TYPE_SIZE)
+    return check_ctz_string (ctor, mulc, zero_val, shift, bits);
+  return false;
+}
+
+/* Match.pd function to match the ctz expression.  */
+extern bool gimple_ctz_table_index (tree, tree *, tree (*)(tree));
+
 /* Recognize count trailing zeroes idiom.
    The canonical form is array[((x & -x) * C) >> SHIFT] where C is a magic
    constant which when multiplied by a power of 2 creates a unique value
@@ -2599,17 +2615,23 @@ check_ctz_string (tree string, unsigned HOST_WIDE_INT 
mulc,
    to the number of trailing zeroes.  Array[0] is returned so the caller can
    emit an appropriate sequence depending on whether ctz (0) is defined on
    the target.  */
+
 static bool
-optimize_count_trailing_zeroes (tree array_ref, tree x, tree mulc,
-                               tree tshift, HOST_WIDE_INT &zero_val)
+simplify_count_trailing_zeroes (gimple_stmt_iterator *gsi)
 {
-  tree type = TREE_TYPE (array_ref);
-  tree array = TREE_OPERAND (array_ref, 0);
+  gimple *stmt = gsi_stmt (*gsi);
+  tree array_ref = gimple_assign_rhs1 (stmt);
+  tree res_ops[3];
+
+  gcc_checking_assert (TREE_CODE (array_ref) == ARRAY_REF);
 
-  gcc_assert (TREE_CODE (mulc) == INTEGER_CST);
-  gcc_assert (TREE_CODE (tshift) == INTEGER_CST);
+  if (!gimple_ctz_table_index (TREE_OPERAND (array_ref, 1), &res_ops[0], NULL))
+    return false;
 
-  tree input_type = TREE_TYPE (x);
+  HOST_WIDE_INT zero_val;
+  tree type = TREE_TYPE (array_ref);
+  tree array = TREE_OPERAND (array_ref, 0);
+  tree input_type = TREE_TYPE (res_ops[0]);
   unsigned input_bits = tree_to_shwi (TYPE_SIZE (input_type));
 
   /* Check the array element type is not wider than 32 bits and the input is
@@ -2627,102 +2649,67 @@ optimize_count_trailing_zeroes (tree array_ref, tree 
x, tree mulc,
   if (!low || !integer_zerop (low))
     return false;
 
-  unsigned shiftval = tree_to_shwi (tshift);
-
   /* Check the shift extracts the top 5..7 bits.  */
+  unsigned shiftval = tree_to_shwi (res_ops[2]);
   if (shiftval < input_bits - 7 || shiftval > input_bits - 5)
     return false;
 
   tree ctor = ctor_for_folding (array);
   if (!ctor)
     return false;
+  unsigned HOST_WIDE_INT val = tree_to_uhwi (res_ops[1]);
+  if (!check_ctz_table (ctor, type, val, zero_val, shiftval, input_bits))
+    return false;
 
-  unsigned HOST_WIDE_INT val = tree_to_uhwi (mulc);
-
-  if (TREE_CODE (ctor) == CONSTRUCTOR)
-    return check_ctz_array (ctor, val, zero_val, shiftval, input_bits);
-
-  if (TREE_CODE (ctor) == STRING_CST
-      && TYPE_PRECISION (type) == CHAR_TYPE_SIZE)
-    return check_ctz_string (ctor, val, zero_val, shiftval, input_bits);
-
-  return false;
-}
-
-/* Match.pd function to match the ctz expression.  */
-extern bool gimple_ctz_table_index (tree, tree *, tree (*)(tree));
+  HOST_WIDE_INT ctz_val = 0;
+  bool zero_ok = CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (input_type),
+                                           ctz_val) == 2;
+  int nargs = 2;
 
-static bool
-simplify_count_trailing_zeroes (gimple_stmt_iterator *gsi)
-{
-  gimple *stmt = gsi_stmt (*gsi);
-  tree array_ref = gimple_assign_rhs1 (stmt);
-  tree res_ops[3];
-  HOST_WIDE_INT zero_val;
-
-  gcc_checking_assert (TREE_CODE (array_ref) == ARRAY_REF);
+  /* If the input value can't be zero, don't special case ctz (0).  */
+  if (tree_expr_nonzero_p (res_ops[0]))
+    {
+      zero_ok = true;
+      zero_val = 0;
+      ctz_val = 0;
+      nargs = 1;
+    }
 
-  if (!gimple_ctz_table_index (TREE_OPERAND (array_ref, 1), &res_ops[0], NULL))
+  /* Skip if there is no value defined at zero, or if we can't easily
+     return the correct value for zero.  */
+  if (!zero_ok)
+    return false;
+  if (zero_val != ctz_val && !(zero_val == 0 && ctz_val == input_bits))
     return false;
 
-  if (optimize_count_trailing_zeroes (array_ref, res_ops[0],
-                                     res_ops[1], res_ops[2], zero_val))
+  gimple_seq seq = NULL;
+  gimple *g;
+  gcall *call = gimple_build_call_internal (IFN_CTZ, nargs, res_ops[0],
+                                           nargs == 1 ? NULL_TREE
+                                           : build_int_cst (integer_type_node,
+                                                            ctz_val));
+  gimple_set_location (call, gimple_location (stmt));
+  gimple_set_lhs (call, make_ssa_name (integer_type_node));
+  gimple_seq_add_stmt (&seq, call);
+
+  tree prev_lhs = gimple_call_lhs (call);
+
+  /* Emit ctz (x) & 31 if ctz (0) is 32 but we need to return 0.  */
+  if (zero_val == 0 && ctz_val == input_bits)
     {
-      tree type = TREE_TYPE (res_ops[0]);
-      HOST_WIDE_INT ctz_val = 0;
-      HOST_WIDE_INT type_size = tree_to_shwi (TYPE_SIZE (type));
-      bool zero_ok
-       = CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type), ctz_val) == 2;
-      int nargs = 2;
-
-      /* If the input value can't be zero, don't special case ctz (0).  */
-      if (tree_expr_nonzero_p (res_ops[0]))
-       {
-         zero_ok = true;
-         zero_val = 0;
-         ctz_val = 0;
-         nargs = 1;
-       }
-
-      /* Skip if there is no value defined at zero, or if we can't easily
-        return the correct value for zero.  */
-      if (!zero_ok)
-       return false;
-      if (zero_val != ctz_val && !(zero_val == 0 && ctz_val == type_size))
-       return false;
-
-      gimple_seq seq = NULL;
-      gimple *g;
-      gcall *call
-       = gimple_build_call_internal (IFN_CTZ, nargs, res_ops[0],
-                                     nargs == 1 ? NULL_TREE
-                                     : build_int_cst (integer_type_node,
-                                                      ctz_val));
-      gimple_set_location (call, gimple_location (stmt));
-      gimple_set_lhs (call, make_ssa_name (integer_type_node));
-      gimple_seq_add_stmt (&seq, call);
-
-      tree prev_lhs = gimple_call_lhs (call);
-
-      /* Emit ctz (x) & 31 if ctz (0) is 32 but we need to return 0.  */
-      if (zero_val == 0 && ctz_val == type_size)
-       {
-         g = gimple_build_assign (make_ssa_name (integer_type_node),
-                                  BIT_AND_EXPR, prev_lhs,
-                                  build_int_cst (integer_type_node,
-                                                 type_size - 1));
-         gimple_set_location (g, gimple_location (stmt));
-         gimple_seq_add_stmt (&seq, g);
-         prev_lhs = gimple_assign_lhs (g);
-       }
-
-      g = gimple_build_assign (gimple_assign_lhs (stmt), NOP_EXPR, prev_lhs);
+      g = gimple_build_assign (make_ssa_name (integer_type_node),
+                              BIT_AND_EXPR, prev_lhs,
+                              build_int_cst (integer_type_node,
+                                             input_bits - 1));
+      gimple_set_location (g, gimple_location (stmt));
       gimple_seq_add_stmt (&seq, g);
-      gsi_replace_with_seq (gsi, seq, true);
-      return true;
+      prev_lhs = gimple_assign_lhs (g);
     }
 
-  return false;
+  g = gimple_build_assign (gimple_assign_lhs (stmt), NOP_EXPR, prev_lhs);
+  gimple_seq_add_stmt (&seq, g);
+  gsi_replace_with_seq (gsi, seq, true);
+  return true;
 }

Reply via email to