[PATCH] Refactor range handling of builtins in vr_values and ranger.
Aldy Hernandez
aldyh@redhat.com
Fri Oct 9 12:32:05 GMT 2020
Hi Jakub.
As the last known expert in this area, would you review this, please? :)
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.
Tested on x86_64, with aarch64 tests still going.
OK provided aarch64 tests finish this century?
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.
---
gcc/gimple-range.cc | 36 ++--
gcc/gimple-range.h | 4 +-
gcc/vr-values.c | 508 +++++++++++++++++++++++---------------------
gcc/vr-values.h | 3 +-
4 files changed, 293 insertions(+), 258 deletions(-)
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 2ca86ed0e4c..a72919fc6c5 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -546,10 +546,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);
@@ -559,8 +562,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,
@@ -576,9 +579,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)
@@ -599,7 +604,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;
@@ -613,7 +618,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;
@@ -657,7 +662,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 ())
{
@@ -722,7 +727,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)
@@ -760,13 +765,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:
@@ -816,6 +821,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.
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index 041dc7c2a97..d806d13c8da 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -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 *);
@@ -167,4 +166,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
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index da0b249278b..836356952dd 100644
--- a/gcc/vr-values.c
+++ b/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,271 +1155,289 @@ check_for_binary_op_overflow (range_query *query,
return true;
}
-/* 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 */
+/* Derive a range from a builtin. Set range in VR and return TRUE if
+ successful. */
-void
-vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
+bool
+vr_values::extract_range_builtin (value_range_equiv *vr, gimple *stmt)
{
- bool sop;
+ 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;
- if (is_gimple_call (stmt))
+ switch (cfn)
{
- 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)
{
- 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)
+ 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)
{
- 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;
+ /* 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;
}
- 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 (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 ()))
{
- 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;
- }
+ maxi = prec - 1 - tree_floor_log2 (vr0->min ());
+ if (mini == -2)
+ mini = 0;
}
- if (TREE_CODE (arg) == SSA_NAME)
+ else if (vr0->kind () == VR_ANTI_RANGE
+ && integer_zerop (vr0->min ()))
{
- 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;
- }
+ maxi = prec - 1;
+ mini = 0;
}
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))
+ /* From clz of VR_RANGE maximum we can compute
+ result minimum. */
+ if (vr0->kind () == VR_RANGE
+ && TREE_CODE (vr0->max ()) == INTEGER_CST)
{
- if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
- && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2)
+ int newmini = prec - 1 - tree_floor_log2 (vr0->max ());
+ if (newmini == prec)
{
- /* 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 (maxi == prec)
+ mini = prec;
}
+ else
+ mini = newmini;
}
- if (TREE_CODE (arg) == SSA_NAME)
+ }
+ 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)
{
- 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)
+ /* 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)
{
- 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 == -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]. */
+ }
+ 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))))
{
- 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));
+ 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;
}
- 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;
- }
+ 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 */
+
+void
+vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
+{
+ bool sop;
+ tree type = gimple_expr_type (stmt);
+
+ if (is_gimple_call (stmt) && extract_range_builtin (vr, stmt))
+ {
+ 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
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index a30f05cbeaa..b0ff68d8e34 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -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;
--
2.26.2
More information about the Gcc-patches
mailing list