break;
CASE_INT_FN (BUILT_IN_FFS):
- case BUILT_IN_FFSIMAX:
target = expand_builtin_unop (target_mode, exp, target,
subtarget, ffs_optab);
if (target)
break;
CASE_INT_FN (BUILT_IN_CLZ):
- case BUILT_IN_CLZIMAX:
target = expand_builtin_unop (target_mode, exp, target,
subtarget, clz_optab);
if (target)
break;
CASE_INT_FN (BUILT_IN_CTZ):
- case BUILT_IN_CTZIMAX:
target = expand_builtin_unop (target_mode, exp, target,
subtarget, ctz_optab);
if (target)
break;
CASE_INT_FN (BUILT_IN_CLRSB):
- case BUILT_IN_CLRSBIMAX:
target = expand_builtin_unop (target_mode, exp, target,
subtarget, clrsb_optab);
if (target)
break;
CASE_INT_FN (BUILT_IN_POPCOUNT):
- case BUILT_IN_POPCOUNTIMAX:
target = expand_builtin_unop (target_mode, exp, target,
subtarget, popcount_optab);
if (target)
break;
CASE_INT_FN (BUILT_IN_PARITY):
- case BUILT_IN_PARITYIMAX:
target = expand_builtin_unop (target_mode, exp, target,
subtarget, parity_optab);
if (target)
break;
CASE_INT_FN (BUILT_IN_CLRSB):
+ if (width > 2 * HOST_BITS_PER_WIDE_INT)
+ return NULL_TREE;
if (width > HOST_BITS_PER_WIDE_INT
&& (hi & ((unsigned HOST_WIDE_INT) 1
<< (width - HOST_BITS_PER_WIDE_INT - 1))) != 0)
--- /dev/null
+/* PR target/29776 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp1" } */
+/* { dg-final { scan-tree-dump-not "link_error" "vrp1"} } */
+/* { dg-final { cleanup-tree-dump "vrp1" } } */
+
+#define A(fn, arg, min, max) \
+ if (__builtin_##fn (arg) < min || __builtin_##fn (arg) > max) \
+ link_error ();
+#define B(fn, min, max) \
+ A (fn, a, min, max) A (fn##l, b, min, max) A (fn##ll, c, min, max)
+#define C(fn, min, sub) \
+ A (fn, a, min, ((int) sizeof (a) * __CHAR_BIT__ - sub)) \
+ A (fn##l, b, min, ((int) sizeof (b) * __CHAR_BIT__ - sub)) \
+ A (fn##ll, c, min, ((int) sizeof (c) * __CHAR_BIT__ - sub))
+#define D(fn, sub1, sub2) \
+ A (fn, a, ((int) sizeof (a) * __CHAR_BIT__ - sub1), \
+ ((int) sizeof (a) * __CHAR_BIT__ - sub2)) \
+ A (fn##l, b, ((int) sizeof (b) * __CHAR_BIT__ - sub1), \
+ ((int) sizeof (b) * __CHAR_BIT__ - sub2)) \
+ A (fn##ll, c, ((int) sizeof (c) * __CHAR_BIT__ - sub1), \
+ ((int) sizeof (c) * __CHAR_BIT__ - sub2))
+
+extern void link_error (void);
+
+unsigned int d;
+unsigned long e;
+unsigned long long f;
+
+void
+foo (unsigned int a, unsigned long b, unsigned long long c)
+{
+ B (parity, 0, 1)
+ C (ffs, 0, 0)
+ C (popcount, 0, 0)
+ C (clz, 0, 0)
+ C (ctz, -1, 0)
+ a &= 63;
+ b &= 63;
+ c &= 63;
+ B (ffs, 0, 6)
+ B (popcount, 0, 6)
+ a += 3; b += 3; c += 3;
+ B (ffs, 1, 7)
+ B (popcount, 1, 7)
+ a = 32U + (d & 1023U);
+ b = 32UL + (e & 1023UL);
+ c = 32ULL + (f & 1023ULL);
+ D (clz, 11, 6)
+ B (ctz, 0, 10)
+}
+
+void
+bar (int a, long b, long long c)
+{
+ C (clrsb, 0, 1)
+}
bool sop = false;
tree type = gimple_expr_type (stmt);
- /* If the call is __builtin_constant_p and the argument is a
- function parameter resolve it to false. This avoids bogus
- array bound warnings.
- ??? We could do this as early as inlining is finished. */
- if (gimple_call_builtin_p (stmt, BUILT_IN_CONSTANT_P))
- {
- tree arg = gimple_call_arg (stmt, 0);
- if (TREE_CODE (arg) == SSA_NAME
- && SSA_NAME_IS_DEFAULT_DEF (arg)
- && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL)
- set_value_range_to_null (vr, type);
- }
- else if (INTEGRAL_TYPE_P (type)
- && gimple_stmt_nonnegative_warnv_p (stmt, &sop))
+ if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
+ {
+ tree fndecl = gimple_call_fndecl (stmt), arg;
+ int mini, maxi, zerov = 0, prec;
+
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ case BUILT_IN_CONSTANT_P:
+ /* If the call is __builtin_constant_p and the argument is a
+ function parameter resolve it to false. This avoids bogus
+ array bound warnings.
+ ??? We could do this as early as inlining is finished. */
+ arg = gimple_call_arg (stmt, 0);
+ if (TREE_CODE (arg) == SSA_NAME
+ && SSA_NAME_IS_DEFAULT_DEF (arg)
+ && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL)
+ {
+ set_value_range_to_null (vr, type);
+ return;
+ }
+ break;
+ /* Both __builtin_ffs* and __builtin_popcount return
+ [0, prec]. */
+ CASE_INT_FN (BUILT_IN_FFS):
+ CASE_INT_FN (BUILT_IN_POPCOUNT):
+ arg = gimple_call_arg (stmt, 0);
+ prec = TYPE_PRECISION (TREE_TYPE (arg));
+ mini = 0;
+ maxi = prec;
+ if (TREE_CODE (arg) == SSA_NAME)
+ {
+ value_range_t *vr0 = get_value_range (arg);
+ /* If arg is non-zero, then ffs or popcount
+ are non-zero. */
+ if (((vr0->type == VR_RANGE
+ && integer_nonzerop (vr0->min))
+ || (vr0->type == VR_ANTI_RANGE
+ && integer_zerop (vr0->min)))
+ && !TREE_OVERFLOW (vr0->min))
+ mini = 1;
+ /* If some high bits are known to be zero,
+ we can decrease the maximum. */
+ if (vr0->type == VR_RANGE
+ && TREE_CODE (vr0->max) == INTEGER_CST
+ && !TREE_OVERFLOW (vr0->max))
+ maxi = tree_floor_log2 (vr0->max) + 1;
+ }
+ goto bitop_builtin;
+ /* __builtin_parity* returns [0, 1]. */
+ CASE_INT_FN (BUILT_IN_PARITY):
+ mini = 0;
+ maxi = 1;
+ goto bitop_builtin;
+ /* __builtin_c[lt]z* return [0, prec-1], except for
+ when the argument is 0, but that is undefined behavior.
+ On many targets where the CLZ RTL or optab value is defined
+ for 0 the value is prec, so include that in the range
+ by default. */
+ CASE_INT_FN (BUILT_IN_CLZ):
+ arg = gimple_call_arg (stmt, 0);
+ prec = TYPE_PRECISION (TREE_TYPE (arg));
+ mini = 0;
+ maxi = prec;
+ if (optab_handler (clz_optab, TYPE_MODE (TREE_TYPE (arg)))
+ != CODE_FOR_nothing
+ && CLZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (TREE_TYPE (arg)),
+ zerov)
+ /* Handle only the single common value. */
+ && zerov != prec)
+ /* Magic value to give up, unless vr0 proves
+ arg is non-zero. */
+ mini = -2;
+ if (TREE_CODE (arg) == SSA_NAME)
+ {
+ value_range_t *vr0 = get_value_range (arg);
+ /* From clz of VR_RANGE minimum we can compute
+ result maximum. */
+ if (vr0->type == VR_RANGE
+ && TREE_CODE (vr0->min) == INTEGER_CST
+ && !TREE_OVERFLOW (vr0->min))
+ {
+ maxi = prec - 1 - tree_floor_log2 (vr0->min);
+ if (maxi != prec)
+ mini = 0;
+ }
+ else if (vr0->type == VR_ANTI_RANGE
+ && integer_zerop (vr0->min)
+ && !TREE_OVERFLOW (vr0->min))
+ {
+ maxi = prec - 1;
+ mini = 0;
+ }
+ if (mini == -2)
+ break;
+ /* From clz of VR_RANGE maximum we can compute
+ result minimum. */
+ if (vr0->type == VR_RANGE
+ && TREE_CODE (vr0->max) == INTEGER_CST
+ && !TREE_OVERFLOW (vr0->max))
+ {
+ mini = prec - 1 - tree_floor_log2 (vr0->max);
+ if (mini == prec)
+ break;
+ }
+ }
+ if (mini == -2)
+ break;
+ goto bitop_builtin;
+ /* __builtin_ctz* return [0, prec-1], except for
+ when the argument is 0, but that is undefined behavior.
+ If there is a ctz optab for this mode and
+ CTZ_DEFINED_VALUE_AT_ZERO, include that in the range,
+ otherwise just assume 0 won't be seen. */
+ CASE_INT_FN (BUILT_IN_CTZ):
+ arg = gimple_call_arg (stmt, 0);
+ prec = TYPE_PRECISION (TREE_TYPE (arg));
+ mini = 0;
+ maxi = prec - 1;
+ if (optab_handler (ctz_optab, TYPE_MODE (TREE_TYPE (arg)))
+ != CODE_FOR_nothing
+ && CTZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (TREE_TYPE (arg)),
+ zerov))
+ {
+ /* Handle only the two common values. */
+ if (zerov == -1)
+ mini = -1;
+ else if (zerov == prec)
+ maxi = prec;
+ else
+ /* Magic value to give up, unless vr0 proves
+ arg is non-zero. */
+ mini = -2;
+ }
+ if (TREE_CODE (arg) == SSA_NAME)
+ {
+ value_range_t *vr0 = get_value_range (arg);
+ /* If arg is non-zero, then use [0, prec - 1]. */
+ if (((vr0->type == VR_RANGE
+ && integer_nonzerop (vr0->min))
+ || (vr0->type == VR_ANTI_RANGE
+ && integer_zerop (vr0->min)))
+ && !TREE_OVERFLOW (vr0->min))
+ {
+ mini = 0;
+ maxi = prec - 1;
+ }
+ /* If some high bits are known to be zero,
+ we can decrease the result maximum. */
+ if (vr0->type == VR_RANGE
+ && TREE_CODE (vr0->max) == INTEGER_CST
+ && !TREE_OVERFLOW (vr0->max))
+ {
+ maxi = tree_floor_log2 (vr0->max);
+ /* For vr0 [0, 0] give up. */
+ if (maxi == -1)
+ break;
+ }
+ }
+ if (mini == -2)
+ break;
+ goto bitop_builtin;
+ /* __builtin_clrsb* returns [0, prec-1]. */
+ CASE_INT_FN (BUILT_IN_CLRSB):
+ arg = gimple_call_arg (stmt, 0);
+ prec = TYPE_PRECISION (TREE_TYPE (arg));
+ mini = 0;
+ maxi = prec - 1;
+ goto bitop_builtin;
+ bitop_builtin:
+ set_value_range (vr, VR_RANGE, build_int_cst (type, mini),
+ build_int_cst (type, maxi), NULL);
+ return;
+ default:
+ break;
+ }
+ }
+ if (INTEGRAL_TYPE_P (type)
+ && gimple_stmt_nonnegative_warnv_p (stmt, &sop))
set_value_range_to_nonnegative (vr, type,
sop || stmt_overflow_infinity (stmt));
else if (vrp_stmt_computes_nonzero (stmt, &sop)