aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-range-op.cc
diff options
context:
space:
mode:
authorAndrew MacLeod <amacleod@redhat.com>2022-09-20 18:19:30 -0400
committerAndrew MacLeod <amacleod@redhat.com>2022-09-22 14:48:29 -0400
commit55738d8d96bb4f39a72cf5e3739d35b39fc2146a (patch)
treee97fd4141f4d1876f2a450a1d391512f870624d3 /gcc/gimple-range-op.cc
parentae1669a98656cca594fcd2fef6bd2cd7308a361f (diff)
downloadgcc-55738d8d96bb4f39a72cf5e3739d35b39fc2146a.zip
gcc-55738d8d96bb4f39a72cf5e3739d35b39fc2146a.tar.gz
gcc-55738d8d96bb4f39a72cf5e3739d35b39fc2146a.tar.bz2
Convert CFN_CTZ builtins to range-ops.
* 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.
Diffstat (limited to 'gcc/gimple-range-op.cc')
-rw-r--r--gcc/gimple-range-op.cc79
1 files changed, 79 insertions, 0 deletions
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index caba493..801c2bb 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -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;
}