Refactor range handling of builtins in vr_values and ranger.
This sets things up so we can share range handling of builtins between vr_values and ranger. It is meant to refactor the code so that we can verify that both implementations yield the same results. First, we abstract out gimple_ranger::range_of_builtin_call into an externally visible counterpart that can be called from vr_values. It will take a range_query since both ranger and vr_values inherit from this base class. Then we abstract out all the builtin handling in vr_values into a separate method that is easier to compare against. Finally, we call the ranger version from vr_values and compare it with the vr_values version. Since this proves both versions return the same, we can remove vr_values::extract_range_builtin in a follow-up patch. The vr_values::range_of_expr change brings the vr_values version up to par with the ranger version. It should've handled non-SSA's. This was a small oversight that went unnoticed because the vr_value version isn't stressed nearly as much as the ranger version. The change is needed because the ranger code handling builtins calls, may call it for integer arguments in range_of_builtin_ubsan_call. There should be no change in functionality. gcc/ChangeLog: * gimple-range.cc (gimple_ranger::range_of_builtin_ubsan_call): Make externally visble... (range_of_builtin_ubsan_call): ...here. Add range_query argument. (gimple_ranger::range_of_builtin_call): Make externally visible... (range_of_builtin_call): ...here. Add range_query argument. * gimple-range.h (range_of_builtin_call): Move out from class and make externally visible. * vr-values.c (vr_values::extract_range_basic): Abstract out builtin handling to... (vr_values::range_of_expr): Handle non SSAs. (vr_values::extract_range_builtin): ...here. * vr-values.h (class vr_values): Add extract_range_builtin. (range_of_expr): Rename NAME to EXPR.
This commit is contained in:
parent
5d53ec2701
commit
16e4f1ad44
@ -552,10 +552,13 @@ gimple_ranger::range_of_call (irange &r, gcall *call)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the range of a __builtin_ubsan* in CALL and set it in R.
|
||||
// CODE is the type of ubsan call (PLUS_EXPR, MINUS_EXPR or
|
||||
// MULT_EXPR).
|
||||
|
||||
void
|
||||
gimple_ranger::range_of_builtin_ubsan_call (irange &r, gcall *call,
|
||||
tree_code code)
|
||||
static void
|
||||
range_of_builtin_ubsan_call (range_query &query, irange &r, gcall *call,
|
||||
tree_code code)
|
||||
{
|
||||
gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR
|
||||
|| code == MULT_EXPR);
|
||||
@ -565,8 +568,8 @@ gimple_ranger::range_of_builtin_ubsan_call (irange &r, gcall *call,
|
||||
int_range_max ir0, ir1;
|
||||
tree arg0 = gimple_call_arg (call, 0);
|
||||
tree arg1 = gimple_call_arg (call, 1);
|
||||
gcc_assert (range_of_expr (ir0, arg0, call));
|
||||
gcc_assert (range_of_expr (ir1, arg1, call));
|
||||
gcc_assert (query.range_of_expr (ir0, arg0, call));
|
||||
gcc_assert (query.range_of_expr (ir1, arg1, call));
|
||||
|
||||
bool saved_flag_wrapv = flag_wrapv;
|
||||
// Pretend the arithmetic is wrapping. If there is any overflow,
|
||||
@ -582,9 +585,11 @@ gimple_ranger::range_of_builtin_ubsan_call (irange &r, gcall *call,
|
||||
r.set_varying (type);
|
||||
}
|
||||
|
||||
// For a builtin in CALL, return a range in R if known and return
|
||||
// TRUE. Otherwise return FALSE.
|
||||
|
||||
bool
|
||||
gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
|
||||
range_of_builtin_call (range_query &query, irange &r, gcall *call)
|
||||
{
|
||||
combined_fn func = gimple_call_combined_fn (call);
|
||||
if (func == CFN_LAST)
|
||||
@ -605,7 +610,7 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
|
||||
return true;
|
||||
}
|
||||
arg = gimple_call_arg (call, 0);
|
||||
if (range_of_expr (r, arg, call) && r.singleton_p ())
|
||||
if (query.range_of_expr (r, arg, call) && r.singleton_p ())
|
||||
{
|
||||
r.set (build_one_cst (type), build_one_cst (type));
|
||||
return true;
|
||||
@ -619,7 +624,7 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
|
||||
prec = TYPE_PRECISION (TREE_TYPE (arg));
|
||||
mini = 0;
|
||||
maxi = prec;
|
||||
gcc_assert (range_of_expr (r, arg, call));
|
||||
gcc_assert (query.range_of_expr (r, arg, call));
|
||||
// If arg is non-zero, then ffs or popcount are non-zero.
|
||||
if (!range_includes_zero_p (&r))
|
||||
mini = 1;
|
||||
@ -663,7 +668,7 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
|
||||
}
|
||||
}
|
||||
|
||||
gcc_assert (range_of_expr (r, arg, call));
|
||||
gcc_assert (query.range_of_expr (r, arg, call));
|
||||
// From clz of minimum we can compute result maximum.
|
||||
if (r.constant_p ())
|
||||
{
|
||||
@ -728,7 +733,7 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
|
||||
mini = -2;
|
||||
}
|
||||
}
|
||||
gcc_assert (range_of_expr (r, arg, call));
|
||||
gcc_assert (query.range_of_expr (r, arg, call));
|
||||
if (!r.undefined_p ())
|
||||
{
|
||||
if (r.lower_bound () != 0)
|
||||
@ -766,13 +771,13 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
|
||||
r.set (build_int_cst (type, 0), build_int_cst (type, prec - 1));
|
||||
return true;
|
||||
case CFN_UBSAN_CHECK_ADD:
|
||||
range_of_builtin_ubsan_call (r, call, PLUS_EXPR);
|
||||
range_of_builtin_ubsan_call (query, r, call, PLUS_EXPR);
|
||||
return true;
|
||||
case CFN_UBSAN_CHECK_SUB:
|
||||
range_of_builtin_ubsan_call (r, call, MINUS_EXPR);
|
||||
range_of_builtin_ubsan_call (query, r, call, MINUS_EXPR);
|
||||
return true;
|
||||
case CFN_UBSAN_CHECK_MUL:
|
||||
range_of_builtin_ubsan_call (r, call, MULT_EXPR);
|
||||
range_of_builtin_ubsan_call (query, r, call, MULT_EXPR);
|
||||
return true;
|
||||
|
||||
case CFN_GOACC_DIM_SIZE:
|
||||
@ -822,6 +827,11 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
|
||||
{
|
||||
return ::range_of_builtin_call (*this, r, call);
|
||||
}
|
||||
|
||||
// Calculate a range for COND_EXPR statement S and return it in R.
|
||||
// If a range cannot be calculated, return false.
|
||||
|
@ -64,7 +64,6 @@ private:
|
||||
bool range_of_phi (irange &r, gphi *phi);
|
||||
bool range_of_non_trivial_assignment (irange &r, gimple *s);
|
||||
bool range_of_builtin_call (irange &r, gcall *call);
|
||||
void range_of_builtin_ubsan_call (irange &r, gcall *call, tree_code code);
|
||||
bool range_with_loop_info (irange &r, tree name);
|
||||
void range_of_ssa_name_with_loop_info (irange &, tree, class loop *,
|
||||
gphi *);
|
||||
@ -179,4 +178,7 @@ private:
|
||||
// Flag to enable debugging the various internal Caches.
|
||||
#define DEBUG_RANGE_CACHE (dump_file && (param_evrp_mode & EVRP_MODE_DEBUG))
|
||||
|
||||
// Temporary external interface to share with vr_values.
|
||||
bool range_of_builtin_call (range_query &query, irange &r, gcall *call);
|
||||
|
||||
#endif // GCC_GIMPLE_RANGE_STMT_H
|
||||
|
534
gcc/vr-values.c
534
gcc/vr-values.c
@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "vr-values.h"
|
||||
#include "cfghooks.h"
|
||||
#include "range-op.h"
|
||||
#include "gimple-range.h"
|
||||
|
||||
/* Set value range VR to a non-negative range of type TYPE. */
|
||||
|
||||
@ -174,9 +175,12 @@ vr_values::get_value_range (const_tree var,
|
||||
}
|
||||
|
||||
bool
|
||||
vr_values::range_of_expr (irange &r, tree name, gimple *stmt)
|
||||
vr_values::range_of_expr (irange &r, tree expr, gimple *stmt)
|
||||
{
|
||||
if (const value_range *vr = get_value_range (name, stmt))
|
||||
if (!gimple_range_ssa_p (expr))
|
||||
return get_tree_range (r, expr);
|
||||
|
||||
if (const value_range *vr = get_value_range (expr, stmt))
|
||||
{
|
||||
if (vr->undefined_p () || vr->varying_p () || vr->constant_p ())
|
||||
r = *vr;
|
||||
@ -1151,6 +1155,271 @@ check_for_binary_op_overflow (range_query *query,
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Derive a range from a builtin. Set range in VR and return TRUE if
|
||||
successful. */
|
||||
|
||||
bool
|
||||
vr_values::extract_range_builtin (value_range_equiv *vr, gimple *stmt)
|
||||
{
|
||||
gcc_assert (is_gimple_call (stmt));
|
||||
tree type = gimple_expr_type (stmt);
|
||||
tree arg;
|
||||
int mini, maxi, zerov = 0, prec;
|
||||
enum tree_code subcode = ERROR_MARK;
|
||||
combined_fn cfn = gimple_call_combined_fn (stmt);
|
||||
scalar_int_mode mode;
|
||||
|
||||
switch (cfn)
|
||||
{
|
||||
case CFN_BUILT_IN_CONSTANT_P:
|
||||
/* Resolve calls to __builtin_constant_p after inlining. */
|
||||
if (cfun->after_inlining)
|
||||
{
|
||||
vr->set_zero (type);
|
||||
vr->equiv_clear ();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
/* Both __builtin_ffs* and __builtin_popcount return
|
||||
[0, prec]. */
|
||||
CASE_CFN_FFS:
|
||||
CASE_CFN_POPCOUNT:
|
||||
arg = gimple_call_arg (stmt, 0);
|
||||
prec = TYPE_PRECISION (TREE_TYPE (arg));
|
||||
mini = 0;
|
||||
maxi = prec;
|
||||
if (TREE_CODE (arg) == SSA_NAME)
|
||||
{
|
||||
const value_range_equiv *vr0 = get_value_range (arg);
|
||||
/* If arg is non-zero, then ffs or popcount are non-zero. */
|
||||
if (range_includes_zero_p (vr0) == 0)
|
||||
mini = 1;
|
||||
/* If some high bits are known to be zero,
|
||||
we can decrease the maximum. */
|
||||
if (vr0->kind () == VR_RANGE
|
||||
&& TREE_CODE (vr0->max ()) == INTEGER_CST
|
||||
&& !operand_less_p (vr0->min (),
|
||||
build_zero_cst (TREE_TYPE (vr0->min ()))))
|
||||
maxi = tree_floor_log2 (vr0->max ()) + 1;
|
||||
}
|
||||
goto bitop_builtin;
|
||||
/* __builtin_parity* returns [0, 1]. */
|
||||
CASE_CFN_PARITY:
|
||||
mini = 0;
|
||||
maxi = 1;
|
||||
goto bitop_builtin;
|
||||
/* __builtin_clz* return [0, prec-1], except for
|
||||
when the argument is 0, but that is undefined behavior.
|
||||
Always handle __builtin_clz* which can be only written
|
||||
by user as UB on 0 and so [0, prec-1] range, and the internal-fn
|
||||
calls depending on how CLZ_DEFINED_VALUE_AT_ZERO is defined. */
|
||||
CASE_CFN_CLZ:
|
||||
arg = gimple_call_arg (stmt, 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 (stmt))
|
||||
{
|
||||
if (optab_handler (clz_optab, mode) != CODE_FOR_nothing
|
||||
&& CLZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
|
||||
{
|
||||
/* Handle only the single common value. */
|
||||
if (zerov == prec)
|
||||
maxi = prec;
|
||||
/* Magic value to give up, unless vr0 proves
|
||||
arg is non-zero. */
|
||||
else
|
||||
mini = -2;
|
||||
}
|
||||
}
|
||||
if (TREE_CODE (arg) == SSA_NAME)
|
||||
{
|
||||
const value_range_equiv *vr0 = get_value_range (arg);
|
||||
/* From clz of VR_RANGE minimum we can compute
|
||||
result maximum. */
|
||||
if (vr0->kind () == VR_RANGE
|
||||
&& TREE_CODE (vr0->min ()) == INTEGER_CST
|
||||
&& integer_nonzerop (vr0->min ()))
|
||||
{
|
||||
maxi = prec - 1 - tree_floor_log2 (vr0->min ());
|
||||
if (mini == -2)
|
||||
mini = 0;
|
||||
}
|
||||
else if (vr0->kind () == VR_ANTI_RANGE
|
||||
&& integer_zerop (vr0->min ()))
|
||||
{
|
||||
maxi = prec - 1;
|
||||
mini = 0;
|
||||
}
|
||||
if (mini == -2)
|
||||
break;
|
||||
/* From clz of VR_RANGE maximum we can compute
|
||||
result minimum. */
|
||||
if (vr0->kind () == VR_RANGE
|
||||
&& TREE_CODE (vr0->max ()) == INTEGER_CST)
|
||||
{
|
||||
int newmini = prec - 1 - tree_floor_log2 (vr0->max ());
|
||||
if (newmini == prec)
|
||||
{
|
||||
if (maxi == prec)
|
||||
mini = prec;
|
||||
}
|
||||
else
|
||||
mini = newmini;
|
||||
}
|
||||
}
|
||||
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.
|
||||
Always handle __builtin_ctz* which can be only written
|
||||
by user as UB on 0 and so [0, prec-1] range, and the internal-fn
|
||||
calls depending on how CTZ_DEFINED_VALUE_AT_ZERO is defined. */
|
||||
CASE_CFN_CTZ:
|
||||
arg = gimple_call_arg (stmt, 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 (stmt))
|
||||
{
|
||||
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 vr0 proves
|
||||
arg is non-zero. */
|
||||
mini = -2;
|
||||
}
|
||||
}
|
||||
if (TREE_CODE (arg) == SSA_NAME)
|
||||
{
|
||||
const value_range_equiv *vr0 = get_value_range (arg);
|
||||
/* If arg is non-zero, then use [0, prec - 1]. */
|
||||
if ((vr0->kind () == VR_RANGE
|
||||
&& integer_nonzerop (vr0->min ()))
|
||||
|| (vr0->kind () == VR_ANTI_RANGE
|
||||
&& integer_zerop (vr0->min ())))
|
||||
{
|
||||
mini = 0;
|
||||
maxi = prec - 1;
|
||||
}
|
||||
/* If some high bits are known to be zero,
|
||||
we can decrease the result maximum. */
|
||||
if (vr0->kind () == VR_RANGE
|
||||
&& TREE_CODE (vr0->max ()) == INTEGER_CST)
|
||||
{
|
||||
int newmaxi = tree_floor_log2 (vr0->max ());
|
||||
if (newmaxi == -1)
|
||||
{
|
||||
if (mini == -1)
|
||||
maxi = -1;
|
||||
else if (maxi == prec)
|
||||
mini = prec;
|
||||
}
|
||||
else if (maxi != prec)
|
||||
maxi = newmaxi;
|
||||
}
|
||||
}
|
||||
if (mini == -2)
|
||||
break;
|
||||
goto bitop_builtin;
|
||||
/* __builtin_clrsb* returns [0, prec-1]. */
|
||||
CASE_CFN_CLRSB:
|
||||
arg = gimple_call_arg (stmt, 0);
|
||||
prec = TYPE_PRECISION (TREE_TYPE (arg));
|
||||
mini = 0;
|
||||
maxi = prec - 1;
|
||||
goto bitop_builtin;
|
||||
bitop_builtin:
|
||||
vr->set (build_int_cst (type, mini), build_int_cst (type, maxi));
|
||||
return true;
|
||||
case CFN_UBSAN_CHECK_ADD:
|
||||
subcode = PLUS_EXPR;
|
||||
break;
|
||||
case CFN_UBSAN_CHECK_SUB:
|
||||
subcode = MINUS_EXPR;
|
||||
break;
|
||||
case CFN_UBSAN_CHECK_MUL:
|
||||
subcode = MULT_EXPR;
|
||||
break;
|
||||
case CFN_GOACC_DIM_SIZE:
|
||||
case CFN_GOACC_DIM_POS:
|
||||
/* Optimizing these two internal functions helps the loop
|
||||
optimizer eliminate outer comparisons. Size is [1,N]
|
||||
and pos is [0,N-1]. */
|
||||
{
|
||||
bool is_pos = cfn == CFN_GOACC_DIM_POS;
|
||||
int axis = oacc_get_ifn_dim_arg (stmt);
|
||||
int size = oacc_get_fn_dim_size (current_function_decl, axis);
|
||||
|
||||
if (!size)
|
||||
/* If it's dynamic, the backend might know a hardware
|
||||
limitation. */
|
||||
size = targetm.goacc.dim_limit (axis);
|
||||
|
||||
tree type = TREE_TYPE (gimple_call_lhs (stmt));
|
||||
vr->set(build_int_cst (type, is_pos ? 0 : 1),
|
||||
size
|
||||
? build_int_cst (type, size - is_pos) : vrp_val_max (type));
|
||||
}
|
||||
return true;
|
||||
case CFN_BUILT_IN_STRLEN:
|
||||
if (tree lhs = gimple_call_lhs (stmt))
|
||||
if (ptrdiff_type_node
|
||||
&& (TYPE_PRECISION (ptrdiff_type_node)
|
||||
== TYPE_PRECISION (TREE_TYPE (lhs))))
|
||||
{
|
||||
tree type = TREE_TYPE (lhs);
|
||||
tree max = vrp_val_max (ptrdiff_type_node);
|
||||
wide_int wmax = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max)));
|
||||
tree range_min = build_zero_cst (type);
|
||||
/* To account for the terminating NUL, the maximum length
|
||||
is one less than the maximum array size, which in turn
|
||||
is one less than PTRDIFF_MAX (or SIZE_MAX where it's
|
||||
smaller than the former type).
|
||||
FIXME: Use max_object_size() - 1 here. */
|
||||
tree range_max = wide_int_to_tree (type, wmax - 2);
|
||||
vr->set (range_min, range_max);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (subcode != ERROR_MARK)
|
||||
{
|
||||
bool saved_flag_wrapv = flag_wrapv;
|
||||
/* Pretend the arithmetics is wrapping. If there is
|
||||
any overflow, we'll complain, but will actually do
|
||||
wrapping operation. */
|
||||
flag_wrapv = 1;
|
||||
extract_range_from_binary_expr (vr, subcode, type,
|
||||
gimple_call_arg (stmt, 0),
|
||||
gimple_call_arg (stmt, 1));
|
||||
flag_wrapv = saved_flag_wrapv;
|
||||
|
||||
/* If for both arguments vrp_valueize returned non-NULL,
|
||||
this should have been already folded and if not, it
|
||||
wasn't folded because of overflow. Avoid removing the
|
||||
UBSAN_CHECK_* calls in that case. */
|
||||
if (vr->kind () == VR_RANGE
|
||||
&& (vr->min () == vr->max ()
|
||||
|| operand_equal_p (vr->min (), vr->max (), 0)))
|
||||
vr->set_varying (vr->type ());
|
||||
|
||||
return !vr->varying_p ();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Try to derive a nonnegative or nonzero range out of STMT relying
|
||||
primarily on generic routines in fold in conjunction with range data.
|
||||
Store the result in *VR */
|
||||
@ -1161,261 +1430,14 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
|
||||
bool sop;
|
||||
tree type = gimple_expr_type (stmt);
|
||||
|
||||
if (is_gimple_call (stmt))
|
||||
if (is_gimple_call (stmt) && extract_range_builtin (vr, stmt))
|
||||
{
|
||||
tree arg;
|
||||
int mini, maxi, zerov = 0, prec;
|
||||
enum tree_code subcode = ERROR_MARK;
|
||||
combined_fn cfn = gimple_call_combined_fn (stmt);
|
||||
scalar_int_mode mode;
|
||||
|
||||
switch (cfn)
|
||||
{
|
||||
case CFN_BUILT_IN_CONSTANT_P:
|
||||
/* Resolve calls to __builtin_constant_p after inlining. */
|
||||
if (cfun->after_inlining)
|
||||
{
|
||||
vr->set_zero (type);
|
||||
vr->equiv_clear ();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
/* Both __builtin_ffs* and __builtin_popcount return
|
||||
[0, prec]. */
|
||||
CASE_CFN_FFS:
|
||||
CASE_CFN_POPCOUNT:
|
||||
arg = gimple_call_arg (stmt, 0);
|
||||
prec = TYPE_PRECISION (TREE_TYPE (arg));
|
||||
mini = 0;
|
||||
maxi = prec;
|
||||
if (TREE_CODE (arg) == SSA_NAME)
|
||||
{
|
||||
const value_range_equiv *vr0 = get_value_range (arg);
|
||||
/* If arg is non-zero, then ffs or popcount are non-zero. */
|
||||
if (range_includes_zero_p (vr0) == 0)
|
||||
mini = 1;
|
||||
/* If some high bits are known to be zero,
|
||||
we can decrease the maximum. */
|
||||
if (vr0->kind () == VR_RANGE
|
||||
&& TREE_CODE (vr0->max ()) == INTEGER_CST
|
||||
&& !operand_less_p (vr0->min (),
|
||||
build_zero_cst (TREE_TYPE (vr0->min ()))))
|
||||
maxi = tree_floor_log2 (vr0->max ()) + 1;
|
||||
}
|
||||
goto bitop_builtin;
|
||||
/* __builtin_parity* returns [0, 1]. */
|
||||
CASE_CFN_PARITY:
|
||||
mini = 0;
|
||||
maxi = 1;
|
||||
goto bitop_builtin;
|
||||
/* __builtin_clz* return [0, prec-1], except for
|
||||
when the argument is 0, but that is undefined behavior.
|
||||
Always handle __builtin_clz* which can be only written
|
||||
by user as UB on 0 and so [0, prec-1] range, and the internal-fn
|
||||
calls depending on how CLZ_DEFINED_VALUE_AT_ZERO is defined. */
|
||||
CASE_CFN_CLZ:
|
||||
arg = gimple_call_arg (stmt, 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 (stmt))
|
||||
{
|
||||
if (optab_handler (clz_optab, mode) != CODE_FOR_nothing
|
||||
&& CLZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
|
||||
{
|
||||
/* Handle only the single common value. */
|
||||
if (zerov == prec)
|
||||
maxi = prec;
|
||||
/* Magic value to give up, unless vr0 proves
|
||||
arg is non-zero. */
|
||||
else
|
||||
mini = -2;
|
||||
}
|
||||
}
|
||||
if (TREE_CODE (arg) == SSA_NAME)
|
||||
{
|
||||
const value_range_equiv *vr0 = get_value_range (arg);
|
||||
/* From clz of VR_RANGE minimum we can compute
|
||||
result maximum. */
|
||||
if (vr0->kind () == VR_RANGE
|
||||
&& TREE_CODE (vr0->min ()) == INTEGER_CST
|
||||
&& integer_nonzerop (vr0->min ()))
|
||||
{
|
||||
maxi = prec - 1 - tree_floor_log2 (vr0->min ());
|
||||
if (mini == -2)
|
||||
mini = 0;
|
||||
}
|
||||
else if (vr0->kind () == VR_ANTI_RANGE
|
||||
&& integer_zerop (vr0->min ()))
|
||||
{
|
||||
maxi = prec - 1;
|
||||
mini = 0;
|
||||
}
|
||||
if (mini == -2)
|
||||
break;
|
||||
/* From clz of VR_RANGE maximum we can compute
|
||||
result minimum. */
|
||||
if (vr0->kind () == VR_RANGE
|
||||
&& TREE_CODE (vr0->max ()) == INTEGER_CST)
|
||||
{
|
||||
int newmini = prec - 1 - tree_floor_log2 (vr0->max ());
|
||||
if (newmini == prec)
|
||||
{
|
||||
if (maxi == prec)
|
||||
mini = prec;
|
||||
}
|
||||
else
|
||||
mini = newmini;
|
||||
}
|
||||
}
|
||||
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.
|
||||
Always handle __builtin_ctz* which can be only written
|
||||
by user as UB on 0 and so [0, prec-1] range, and the internal-fn
|
||||
calls depending on how CTZ_DEFINED_VALUE_AT_ZERO is defined. */
|
||||
CASE_CFN_CTZ:
|
||||
arg = gimple_call_arg (stmt, 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 (stmt))
|
||||
{
|
||||
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 vr0 proves
|
||||
arg is non-zero. */
|
||||
mini = -2;
|
||||
}
|
||||
}
|
||||
if (TREE_CODE (arg) == SSA_NAME)
|
||||
{
|
||||
const value_range_equiv *vr0 = get_value_range (arg);
|
||||
/* If arg is non-zero, then use [0, prec - 1]. */
|
||||
if ((vr0->kind () == VR_RANGE
|
||||
&& integer_nonzerop (vr0->min ()))
|
||||
|| (vr0->kind () == VR_ANTI_RANGE
|
||||
&& integer_zerop (vr0->min ())))
|
||||
{
|
||||
mini = 0;
|
||||
maxi = prec - 1;
|
||||
}
|
||||
/* If some high bits are known to be zero,
|
||||
we can decrease the result maximum. */
|
||||
if (vr0->kind () == VR_RANGE
|
||||
&& TREE_CODE (vr0->max ()) == INTEGER_CST)
|
||||
{
|
||||
int newmaxi = tree_floor_log2 (vr0->max ());
|
||||
if (newmaxi == -1)
|
||||
{
|
||||
if (mini == -1)
|
||||
maxi = -1;
|
||||
else if (maxi == prec)
|
||||
mini = prec;
|
||||
}
|
||||
else if (maxi != prec)
|
||||
maxi = newmaxi;
|
||||
}
|
||||
}
|
||||
if (mini == -2)
|
||||
break;
|
||||
goto bitop_builtin;
|
||||
/* __builtin_clrsb* returns [0, prec-1]. */
|
||||
CASE_CFN_CLRSB:
|
||||
arg = gimple_call_arg (stmt, 0);
|
||||
prec = TYPE_PRECISION (TREE_TYPE (arg));
|
||||
mini = 0;
|
||||
maxi = prec - 1;
|
||||
goto bitop_builtin;
|
||||
bitop_builtin:
|
||||
vr->set (build_int_cst (type, mini), build_int_cst (type, maxi));
|
||||
return;
|
||||
case CFN_UBSAN_CHECK_ADD:
|
||||
subcode = PLUS_EXPR;
|
||||
break;
|
||||
case CFN_UBSAN_CHECK_SUB:
|
||||
subcode = MINUS_EXPR;
|
||||
break;
|
||||
case CFN_UBSAN_CHECK_MUL:
|
||||
subcode = MULT_EXPR;
|
||||
break;
|
||||
case CFN_GOACC_DIM_SIZE:
|
||||
case CFN_GOACC_DIM_POS:
|
||||
/* Optimizing these two internal functions helps the loop
|
||||
optimizer eliminate outer comparisons. Size is [1,N]
|
||||
and pos is [0,N-1]. */
|
||||
{
|
||||
bool is_pos = cfn == CFN_GOACC_DIM_POS;
|
||||
int axis = oacc_get_ifn_dim_arg (stmt);
|
||||
int size = oacc_get_fn_dim_size (current_function_decl, axis);
|
||||
|
||||
if (!size)
|
||||
/* If it's dynamic, the backend might know a hardware
|
||||
limitation. */
|
||||
size = targetm.goacc.dim_limit (axis);
|
||||
|
||||
tree type = TREE_TYPE (gimple_call_lhs (stmt));
|
||||
vr->set(build_int_cst (type, is_pos ? 0 : 1),
|
||||
size
|
||||
? build_int_cst (type, size - is_pos) : vrp_val_max (type));
|
||||
}
|
||||
return;
|
||||
case CFN_BUILT_IN_STRLEN:
|
||||
if (tree lhs = gimple_call_lhs (stmt))
|
||||
if (ptrdiff_type_node
|
||||
&& (TYPE_PRECISION (ptrdiff_type_node)
|
||||
== TYPE_PRECISION (TREE_TYPE (lhs))))
|
||||
{
|
||||
tree type = TREE_TYPE (lhs);
|
||||
tree max = vrp_val_max (ptrdiff_type_node);
|
||||
wide_int wmax = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max)));
|
||||
tree range_min = build_zero_cst (type);
|
||||
/* To account for the terminating NUL, the maximum length
|
||||
is one less than the maximum array size, which in turn
|
||||
is one less than PTRDIFF_MAX (or SIZE_MAX where it's
|
||||
smaller than the former type).
|
||||
FIXME: Use max_object_size() - 1 here. */
|
||||
tree range_max = wide_int_to_tree (type, wmax - 2);
|
||||
vr->set (range_min, range_max);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (subcode != ERROR_MARK)
|
||||
{
|
||||
bool saved_flag_wrapv = flag_wrapv;
|
||||
/* Pretend the arithmetics is wrapping. If there is
|
||||
any overflow, we'll complain, but will actually do
|
||||
wrapping operation. */
|
||||
flag_wrapv = 1;
|
||||
extract_range_from_binary_expr (vr, subcode, type,
|
||||
gimple_call_arg (stmt, 0),
|
||||
gimple_call_arg (stmt, 1));
|
||||
flag_wrapv = saved_flag_wrapv;
|
||||
|
||||
/* If for both arguments vrp_valueize returned non-NULL,
|
||||
this should have been already folded and if not, it
|
||||
wasn't folded because of overflow. Avoid removing the
|
||||
UBSAN_CHECK_* calls in that case. */
|
||||
if (vr->kind () == VR_RANGE
|
||||
&& (vr->min () == vr->max ()
|
||||
|| operand_equal_p (vr->min (), vr->max (), 0)))
|
||||
vr->set_varying (vr->type ());
|
||||
return;
|
||||
}
|
||||
value_range_equiv tmp;
|
||||
/* Assert that any ranges vr_values::extract_range_builtin gets
|
||||
are also handled by the ranger counterpart. */
|
||||
gcc_assert (range_of_builtin_call (*this, tmp, as_a<gcall *> (stmt)));
|
||||
gcc_assert (tmp.equal_p (*vr, /*ignore_equivs=*/false));
|
||||
return;
|
||||
}
|
||||
/* Handle extraction of the two results (result of arithmetics and
|
||||
a flag whether arithmetics overflowed) from {ADD,SUB,MUL}_OVERFLOW
|
||||
|
@ -101,7 +101,7 @@ class vr_values : public range_query
|
||||
vr_values (void);
|
||||
~vr_values (void);
|
||||
|
||||
virtual bool range_of_expr (irange &r, tree name, gimple *stmt) OVERRIDE;
|
||||
virtual bool range_of_expr (irange &r, tree expr, gimple *stmt) OVERRIDE;
|
||||
virtual tree value_of_expr (tree, gimple * = NULL) OVERRIDE;
|
||||
virtual tree value_on_edge (edge, tree) OVERRIDE;
|
||||
virtual tree value_of_stmt (gimple *, tree = NULL_TREE) OVERRIDE;
|
||||
@ -148,6 +148,7 @@ class vr_values : public range_query
|
||||
void extract_range_from_comparison (value_range_equiv *, gimple *);
|
||||
void vrp_visit_assignment_or_call (gimple*, tree *, value_range_equiv *);
|
||||
void vrp_visit_switch_stmt (gswitch *, edge *);
|
||||
bool extract_range_builtin (value_range_equiv *, gimple *);
|
||||
|
||||
/* This probably belongs in the lattice rather than in here. */
|
||||
bool values_propagated;
|
||||
|
Loading…
Reference in New Issue
Block a user