From 16e4f1ad44e3c00b8b73c9e4ade3d236ea7044a8 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 9 Oct 2020 11:26:33 +0200 Subject: [PATCH] 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. --- 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 ed9609be68e..b790d62d75f 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -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. diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index a6e8793f284..0aa6d4672ee 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 *); @@ -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 diff --git a/gcc/vr-values.c b/gcc/vr-values.c index e917704d9bb..11beef82a64 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 (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.30.2