]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Convert CFN_CTZ builtins to range-ops.
authorAndrew MacLeod <amacleod@redhat.com>
Tue, 20 Sep 2022 22:19:30 +0000 (18:19 -0400)
committerAndrew MacLeod <amacleod@redhat.com>
Thu, 22 Sep 2022 18:48:29 +0000 (14:48 -0400)
* gimple-range-fold.cc (range_of_builtin_int_call): Remove case
for CFN_CTZ.
* gimple-range-op.cc (class cfn_ctz): New.
(gimple_range_op_handler::maybe_builtin_call): Set arguments.

gcc/gimple-range-fold.cc
gcc/gimple-range-op.cc

index 63eaa90be96b684ca4bfc6a79710932487121881..96a138a7a022c23852e601e8d5e9a3ddcbeb95ac 100644 (file)
@@ -917,7 +917,7 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
 
   tree type = gimple_range_type (call);
   tree arg;
-  int mini, maxi, zerov = 0, prec;
+  int prec;
   scalar_int_mode mode;
 
   switch (func)
@@ -926,65 +926,6 @@ fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
       r.set (build_zero_cst (type), build_one_cst (type));
       return true;
 
-    CASE_CFN_CTZ:
-      // __builtin_ctz* return [0, prec-1], except for when the
-      // argument is 0, but that is undefined behavior.
-      //
-      // For __builtin_ctz* consider argument of 0 always undefined
-      // behavior, for internal fns depending on CTZ_DEFINED_VALUE_AT_ZERO.
-      arg = gimple_call_arg (call, 0);
-      prec = TYPE_PRECISION (TREE_TYPE (arg));
-      mini = 0;
-      maxi = prec - 1;
-      mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg));
-      if (gimple_call_internal_p (call))
-       {
-         if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
-             && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
-           {
-             // Handle only the two common values.
-             if (zerov == -1)
-               mini = -1;
-             else if (zerov == prec)
-               maxi = prec;
-             else
-               // Magic value to give up, unless we can prove arg is non-zero.
-               mini = -2;
-           }
-       }
-      src.get_operand (r, arg);
-      if (!r.undefined_p ())
-       {
-         // If arg is non-zero, then use [0, prec - 1].
-         if (!range_includes_zero_p (&r))
-           {
-             mini = 0;
-             maxi = prec - 1;
-           }
-         // If some high bits are known to be zero, we can decrease
-         // the maximum.
-         wide_int max = r.upper_bound ();
-         if (max == 0)
-           {
-             // Argument is [0, 0].  If CTZ_DEFINED_VALUE_AT_ZERO
-             // is 2 with value -1 or prec, return [-1, -1] or [prec, prec].
-             // Otherwise ignore the range.
-             if (mini == -1)
-               maxi = -1;
-             else if (maxi == prec)
-               mini = prec;
-           }
-         // If value at zero is prec and 0 is in the range, we can't lower
-         // the upper bound.  We could create two separate ranges though,
-         // [0,floor_log2(max)][prec,prec] though.
-         else if (maxi != prec)
-           maxi = wi::floor_log2 (max);
-       }
-      if (mini == -2)
-       break;
-      r.set (build_int_cst (type, mini), build_int_cst (type, maxi));
-      return true;
-
     CASE_CFN_CLRSB:
       arg = gimple_call_arg (call, 0);
       prec = TYPE_PRECISION (TREE_TYPE (arg));
index caba49309f922f6a0c4e4f0f19b27979641c9712..801c2bb235e23051d61bbb74ccffa5108760fd3e 100644 (file)
@@ -489,6 +489,76 @@ cfn_clz::fold_range (irange &r, tree type, const irange &lh,
   return true;
 }
 
+// Implement range operator for CFN_BUILT_IN_CTZ
+class cfn_ctz : public range_operator
+{
+public:
+  cfn_ctz (bool internal) { m_gimple_call_internal_p = internal; }
+  using range_operator::fold_range;
+  virtual bool fold_range (irange &r, tree type, const irange &lh,
+                          const irange &, relation_kind) const;
+private:
+  bool m_gimple_call_internal_p;
+} op_cfn_ctz (false), op_cfn_ctz_internal (true);
+
+bool
+cfn_ctz::fold_range (irange &r, tree type, const irange &lh,
+                    const irange &, relation_kind) const
+{
+  if (lh.undefined_p ())
+    return false;
+  int prec = TYPE_PRECISION (lh.type ());
+  int mini = 0;
+  int maxi = prec - 1;
+  int zerov = 0;
+  scalar_int_mode mode = SCALAR_INT_TYPE_MODE (lh.type ());
+
+  if (m_gimple_call_internal_p)
+    {
+      if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
+         && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
+       {
+         // Handle only the two common values.
+         if (zerov == -1)
+           mini = -1;
+         else if (zerov == prec)
+           maxi = prec;
+         else
+           // Magic value to give up, unless we can prove arg is non-zero.
+           mini = -2;
+       }
+    }
+  // If arg is non-zero, then use [0, prec - 1].
+  if (!range_includes_zero_p (&lh))
+    {
+      mini = 0;
+      maxi = prec - 1;
+    }
+  // If some high bits are known to be zero, we can decrease
+  // the maximum.
+  wide_int max = lh.upper_bound ();
+  if (max == 0)
+    {
+      // Argument is [0, 0].  If CTZ_DEFINED_VALUE_AT_ZERO
+      // is 2 with value -1 or prec, return [-1, -1] or [prec, prec].
+      // Otherwise ignore the range.
+      if (mini == -1)
+       maxi = -1;
+      else if (maxi == prec)
+       mini = prec;
+    }
+  // If value at zero is prec and 0 is in the range, we can't lower
+  // the upper bound.  We could create two separate ranges though,
+  // [0,floor_log2(max)][prec,prec] though.
+  else if (maxi != prec)
+    maxi = wi::floor_log2 (max);
+
+  if (mini == -2)
+    return false;
+  r.set (build_int_cst (type, mini), build_int_cst (type, maxi));
+  return true;
+}
+
 // Set up a gimple_range_op_handler for any built in function which can be
 // supported via range-ops.
 
@@ -553,6 +623,15 @@ gimple_range_op_handler::maybe_builtin_call ()
        m_int = &op_cfn_clz;
       break;
 
+    CASE_CFN_CTZ:
+      m_op1 = gimple_call_arg (call, 0);
+      m_valid = true;
+      if (gimple_call_internal_p (call))
+       m_int = &op_cfn_ctz_internal;
+      else
+       m_int = &op_cfn_ctz;
+      break;
+
     default:
       break;
     }