From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1011) id CE2DA3857C75; Fri, 16 Apr 2021 13:25:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CE2DA3857C75 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Andrew Macleod To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/users/aldyh/heads/ranger-relational)] remove the code from gimple-range that is now in gimple-fold-range. X-Act-Checkin: gcc X-Git-Author: Andrew MacLeod X-Git-Refname: refs/users/aldyh/heads/ranger-relational X-Git-Oldrev: 05dedfb8b5cfa7e25737cc41ea9e563ec040b576 X-Git-Newrev: a46d4f912da76bf93d09a68bc0a17abe7f7b2f1e Message-Id: <20210416132521.CE2DA3857C75@sourceware.org> Date: Fri, 16 Apr 2021 13:25:21 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 16 Apr 2021 13:25:21 -0000 https://gcc.gnu.org/g:a46d4f912da76bf93d09a68bc0a17abe7f7b2f1e commit a46d4f912da76bf93d09a68bc0a17abe7f7b2f1e Author: Andrew MacLeod Date: Thu Apr 15 15:45:11 2021 -0400 remove the code from gimple-range that is now in gimple-fold-range. Diff: --- gcc/gimple-range.cc | 612 ---------------------------------------------------- gcc/gimple-range.h | 10 - gcc/vr-values.c | 3 +- 3 files changed, 2 insertions(+), 623 deletions(-) diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index e68907319ee..8fc7d3d42e7 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -376,595 +376,6 @@ gimple_ranger::~gimple_ranger () delete m_oracle; } -bool -gimple_ranger::calc_stmt (irange &r, gimple *s, tree name) -{ - bool res = false; - // If name is specified, make sure it is an LHS of S. - gcc_checking_assert (name ? SSA_NAME_DEF_STMT (name) == s : true); - - if (gimple_range_handler (s)) - res = range_of_range_op (r, s); - else if (is_a(s)) - res = range_of_phi (r, as_a (s)); - else if (is_a(s)) - res = range_of_call (r, as_a (s)); - else if (is_a (s) && gimple_assign_rhs_code (s) == COND_EXPR) - res = range_of_cond_expr (r, as_a (s)); - - if (!res) - { - // If no name is specified, try the expression kind. - if (!name) - { - tree t = gimple_expr_type (s); - if (!irange::supports_type_p (t)) - return false; - r.set_varying (t); - return true; - } - if (!gimple_range_ssa_p (name)) - return false; - // We don't understand the stmt, so return the global range. - r = gimple_range_global (name); - return true; - } - - if (r.undefined_p ()) - return true; - - // We sometimes get compatible types copied from operands, make sure - // the correct type is being returned. - if (name && TREE_TYPE (name) != r.type ()) - { - gcc_checking_assert (range_compatible_p (r.type (), TREE_TYPE (name))); - range_cast (r, TREE_TYPE (name)); - } - return true; -} - -// Calculate a range for range_op statement S and return it in R. If any -// If a range cannot be calculated, return false. - -bool -gimple_ranger::range_of_range_op (irange &r, gimple *s) -{ - int_range_max range1, range2; - tree lhs = gimple_get_lhs (s); - tree type = gimple_expr_type (s); - gcc_checking_assert (irange::supports_type_p (type)); - - tree op1 = gimple_range_operand1 (s); - tree op2 = gimple_range_operand2 (s); - - if (lhs) - { - // Register potential dependencies for stale value tracking. - m_cache.register_dependency (lhs, op1); - m_cache.register_dependency (lhs, op2); - } - - if (gimple_code (s) == GIMPLE_ASSIGN - && gimple_assign_rhs_code (s) == ADDR_EXPR) - return range_of_address (r, s); - - if (range_of_expr (range1, op1, s)) - { - if (!op2) - { - gimple_range_fold (r, s, range1); -// m_cache.process_relations (s, r, op1, range1); - return true; - } - - if (range_of_expr (range2, op2, s)) - { - relation_kind rel = query_relation (s, op1, op2, false); - if (dump_file && (dump_flags & TDF_DETAILS) && rel != VREL_NONE) - { - fprintf (dump_file, " folding with relation "); - print_relation (dump_file, rel); - fputc ('\n', dump_file); - } - gimple_range_fold (r, s, range1, range2, rel); -// m_cache.process_relations (s, r, op1, range1, op2, range2); - return true; - } - } - r.set_varying (type); - return true; -} - -// Calculate the range of an assignment containing an ADDR_EXPR. -// Return the range in R. -// If a range cannot be calculated, set it to VARYING and return true. - -bool -gimple_ranger::range_of_address (irange &r, gimple *stmt) -{ - gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN); - gcc_checking_assert (gimple_assign_rhs_code (stmt) == ADDR_EXPR); - - bool strict_overflow_p; - tree expr = gimple_assign_rhs1 (stmt); - poly_int64 bitsize, bitpos; - tree offset; - machine_mode mode; - int unsignedp, reversep, volatilep; - tree base = get_inner_reference (TREE_OPERAND (expr, 0), &bitsize, - &bitpos, &offset, &mode, &unsignedp, - &reversep, &volatilep); - - - if (base != NULL_TREE - && TREE_CODE (base) == MEM_REF - && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME) - { - tree ssa = TREE_OPERAND (base, 0); - gcc_checking_assert (irange::supports_type_p (TREE_TYPE (ssa))); - range_of_expr (r, ssa, stmt); - range_cast (r, TREE_TYPE (gimple_assign_rhs1 (stmt))); - - poly_offset_int off = 0; - bool off_cst = false; - if (offset == NULL_TREE || TREE_CODE (offset) == INTEGER_CST) - { - off = mem_ref_offset (base); - if (offset) - off += poly_offset_int::from (wi::to_poly_wide (offset), - SIGNED); - off <<= LOG2_BITS_PER_UNIT; - off += bitpos; - off_cst = true; - } - /* If &X->a is equal to X, the range of X is the result. */ - if (off_cst && known_eq (off, 0)) - return true; - else if (flag_delete_null_pointer_checks - && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr))) - { - /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't - allow going from non-NULL pointer to NULL. */ - if(!range_includes_zero_p (&r)) - return true; - } - /* If MEM_REF has a "positive" offset, consider it non-NULL - always, for -fdelete-null-pointer-checks also "negative" - ones. Punt for unknown offsets (e.g. variable ones). */ - if (!TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr)) - && off_cst - && known_ne (off, 0) - && (flag_delete_null_pointer_checks || known_gt (off, 0))) - { - r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); - return true; - } - r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt))); - return true; - } - - // Handle "= &a". - if (tree_single_nonzero_warnv_p (expr, &strict_overflow_p)) - { - r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); - return true; - } - - // Otherwise return varying. - r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt))); - return true; -} - -// Calculate a range for phi statement S and return it in R. -// If a range cannot be calculated, return false. - -bool -gimple_ranger::range_of_phi (irange &r, gphi *phi) -{ - tree phi_def = gimple_phi_result (phi); - tree type = TREE_TYPE (phi_def); - int_range_max arg_range; - unsigned x; - - if (!irange::supports_type_p (type)) - return false; - - // Start with an empty range, unioning in each argument's range. - r.set_undefined (); - for (x = 0; x < gimple_phi_num_args (phi); x++) - { - tree arg = gimple_phi_arg_def (phi, x); - edge e = gimple_phi_arg_edge (phi, x); - - // Register potential dependencies for stale value tracking. - m_cache.register_dependency (phi_def, arg); - - range_on_edge (arg_range, e, arg); - r.union_ (arg_range); - // Once the value reaches varying, stop looking. - if (r.varying_p ()) - break; - } - - // If SCEV is available, query if this PHI has any knonwn values. - if (scev_initialized_p () && !POINTER_TYPE_P (TREE_TYPE (phi_def))) - { - value_range loop_range; - class loop *l = loop_containing_stmt (phi); - if (l && loop_outer (l)) - { - range_of_ssa_name_with_loop_info (loop_range, phi_def, l, phi); - if (!loop_range.varying_p ()) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, " Loops range found for "); - print_generic_expr (dump_file, phi_def, TDF_SLIM); - fprintf (dump_file, ": "); - loop_range.dump (dump_file); - fprintf (dump_file, " and calculated range :"); - r.dump (dump_file); - fprintf (dump_file, "\n"); - } - r.intersect (loop_range); - } - } - } - - return true; -} - -// Calculate a range for call statement S and return it in R. -// If a range cannot be calculated, return false. - -bool -gimple_ranger::range_of_call (irange &r, gcall *call) -{ - tree type = gimple_call_return_type (call); - tree lhs = gimple_call_lhs (call); - bool strict_overflow_p; - - if (!irange::supports_type_p (type)) - return false; - - if (range_of_builtin_call (r, call)) - ; - else if (gimple_stmt_nonnegative_warnv_p (call, &strict_overflow_p)) - r.set (build_int_cst (type, 0), TYPE_MAX_VALUE (type)); - else if (gimple_call_nonnull_result_p (call) - || gimple_call_nonnull_arg (call)) - r = range_nonzero (type); - else - r.set_varying (type); - - // If there is an LHS, intersect that with what is known. - if (lhs) - { - value_range def; - def = gimple_range_global (lhs); - r.intersect (def); - } - 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). - -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); - tree type = gimple_call_return_type (call); - range_operator *op = range_op_handler (code, type); - gcc_checking_assert (op); - int_range_max ir0, ir1; - tree arg0 = gimple_call_arg (call, 0); - tree arg1 = gimple_call_arg (call, 1); - query.range_of_expr (ir0, arg0, call); - query.range_of_expr (ir1, arg1, call); - - bool saved_flag_wrapv = flag_wrapv; - // Pretend the arithmetic is wrapping. If there is any overflow, - // we'll complain, but will actually do wrapping operation. - flag_wrapv = 1; - op->fold_range (r, type, ir0, ir1); - 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 (r.singleton_p ()) - r.set_varying (type); -} - -// For a builtin in CALL, return a range in R if known and return -// TRUE. Otherwise return FALSE. - -bool -range_of_builtin_call (range_query &query, irange &r, gcall *call) -{ - combined_fn func = gimple_call_combined_fn (call); - if (func == CFN_LAST) - return false; - - tree type = gimple_call_return_type (call); - tree arg; - int mini, maxi, zerov = 0, prec; - scalar_int_mode mode; - - switch (func) - { - case CFN_BUILT_IN_CONSTANT_P: - if (cfun->after_inlining) - { - r.set_zero (type); - // r.equiv_clear (); - return true; - } - arg = gimple_call_arg (call, 0); - if (query.range_of_expr (r, arg, call) && r.singleton_p ()) - { - r.set (build_one_cst (type), build_one_cst (type)); - return true; - } - break; - - CASE_CFN_FFS: - CASE_CFN_POPCOUNT: - // __builtin_ffs* and __builtin_popcount* return [0, prec]. - arg = gimple_call_arg (call, 0); - prec = TYPE_PRECISION (TREE_TYPE (arg)); - mini = 0; - maxi = prec; - 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; - // If some high bits are known to be zero, decrease the maximum. - if (!r.undefined_p ()) - { - if (TYPE_SIGN (r.type ()) == SIGNED) - range_cast (r, unsigned_type_for (r.type ())); - wide_int max = r.upper_bound (); - maxi = wi::floor_log2 (max) + 1; - } - r.set (build_int_cst (type, mini), build_int_cst (type, maxi)); - return true; - - CASE_CFN_PARITY: - r.set (build_zero_cst (type), build_one_cst (type)); - return true; - - CASE_CFN_CLZ: - // __builtin_c[lt]z* return [0, prec-1], except when the - // argument is 0, but that is undefined behavior. - // - // For __builtin_c[lt]z* consider argument of 0 always undefined - // behavior, for internal fns depending on C?Z_DEFINED_VALUE_AT_ZERO. - arg = gimple_call_arg (call, 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 (call)) - { - if (optab_handler (clz_optab, mode) != CODE_FOR_nothing - && CLZ_DEFINED_VALUE_AT_ZERO (mode, zerov) == 2) - { - // Only handle the single common value. - if (zerov == prec) - maxi = prec; - else - // Magic value to give up, unless we can prove arg is non-zero. - mini = -2; - } - } - - query.range_of_expr (r, arg, call); - // From clz of minimum we can compute result maximum. - if (r.constant_p ()) - { - int newmaxi = prec - 1 - wi::floor_log2 (r.lower_bound ()); - // Argument is unsigned, so do nothing if it is [0, ...] range. - if (newmaxi != prec) - { - mini = 0; - maxi = newmaxi; - } - } - else if (!range_includes_zero_p (&r)) - { - maxi = prec - 1; - mini = 0; - } - if (mini == -2) - break; - // From clz of maximum we can compute result minimum. - if (r.constant_p ()) - { - int newmini = prec - 1 - wi::floor_log2 (r.upper_bound ()); - if (newmini == prec) - { - // Argument range is [0, 0]. If CLZ_DEFINED_VALUE_AT_ZERO - // is 2 with VALUE of prec, return [prec, prec], otherwise - // ignore the range. - if (maxi == prec) - mini = prec; - } - else - mini = newmini; - } - if (mini == -2) - break; - r.set (build_int_cst (type, mini), build_int_cst (type, maxi)); - return true; - - CASE_CFN_CTZ: - // __builtin_ctz* return [0, prec-1], except for when the - // argument is 0, but that is undefined behavior. - // - // For __builtin_ctz* consider argument of 0 always undefined - // behavior, for internal fns depending on CTZ_DEFINED_VALUE_AT_ZERO. - arg = gimple_call_arg (call, 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 (call)) - { - 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; - } - } - query.range_of_expr (r, arg, call); - if (!r.undefined_p ()) - { - if (r.lower_bound () != 0) - { - mini = 0; - maxi = prec - 1; - } - // If some high bits are known to be zero, we can decrease - // the maximum. - wide_int max = r.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) - break; - r.set (build_int_cst (type, mini), build_int_cst (type, maxi)); - return true; - - CASE_CFN_CLRSB: - arg = gimple_call_arg (call, 0); - prec = TYPE_PRECISION (TREE_TYPE (arg)); - 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 (query, r, call, PLUS_EXPR); - return true; - case CFN_UBSAN_CHECK_SUB: - range_of_builtin_ubsan_call (query, r, call, MINUS_EXPR); - return true; - case CFN_UBSAN_CHECK_MUL: - range_of_builtin_ubsan_call (query, r, call, MULT_EXPR); - return true; - - 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 = func == CFN_GOACC_DIM_POS; - int axis = oacc_get_ifn_dim_arg (call); - 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); - - r.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 (call)) - 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 NULL, 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); - r.set (range_min, range_max); - return true; - } - break; - default: - break; - } - return false; -} - - -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. - -bool -gimple_ranger::range_of_cond_expr (irange &r, gassign *s) -{ - int_range_max cond_range, range1, range2; - tree cond = gimple_assign_rhs1 (s); - tree op1 = gimple_assign_rhs2 (s); - tree op2 = gimple_assign_rhs3 (s); - - gcc_checking_assert (gimple_assign_rhs_code (s) == COND_EXPR); - gcc_checking_assert (useless_type_conversion_p (TREE_TYPE (op1), - TREE_TYPE (op2))); - if (!irange::supports_type_p (TREE_TYPE (op1))) - return false; - - range_of_expr (cond_range, cond, s); - range_of_expr (range1, op1, s); - range_of_expr (range2, op2, s); - - // If the condition is known, choose the appropriate expression. - if (cond_range.singleton_p ()) - { - // False, pick second operand. - if (cond_range.zero_p ()) - r = range2; - else - r = range1; - } - else - { - r = range1; - r.union_ (range2); - } - return true; -} bool gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) @@ -1270,29 +681,6 @@ gimple_ranger::dump (FILE *f) m_cache.dump (f, false); } -// If SCEV has any information about phi node NAME, return it as a range in R. - -void -gimple_ranger::range_of_ssa_name_with_loop_info (irange &r, tree name, - class loop *l, gphi *phi) -{ - gcc_checking_assert (TREE_CODE (name) == SSA_NAME); - tree min, max, type = TREE_TYPE (name); - if (bounds_of_var_in_loop (&min, &max, this, l, phi, name)) - { - // ?? We could do better here. Since MIN/MAX can only be an - // SSA, SSA +- INTEGER_CST, or INTEGER_CST, we could easily call - // the ranger and solve anything not an integer. - if (TREE_CODE (min) != INTEGER_CST) - min = vrp_val_min (type); - if (TREE_CODE (max) != INTEGER_CST) - max = vrp_val_max (type); - r.set (min, max); - } - else - r.set_varying (type); -} - // -------------------------------------------------------------------------- // trace_ranger implementation. diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index 4087154695d..a0cec71582d 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -58,18 +58,8 @@ public: void dump (FILE *f); void dump_bb (FILE *f, basic_block bb); protected: - bool calc_stmt (irange &r, gimple *s, tree name = NULL_TREE); - bool range_of_range_op (irange &r, gimple *s); - bool range_of_call (irange &r, gcall *call); - bool range_of_cond_expr (irange &r, gassign* cond); ranger_cache m_cache; private: - bool range_of_phi (irange &r, gphi *phi); - bool range_of_address (irange &r, gimple *s); - bool range_of_builtin_call (irange &r, gcall *call); - bool range_with_loop_info (irange &r, tree name); - void range_of_ssa_name_with_loop_info (irange &, tree, class loop *, - gphi *); }; // Calculate a basic range for a tree expression. diff --git a/gcc/vr-values.c b/gcc/vr-values.c index fed8593e992..0c1babdb3d2 100644 --- a/gcc/vr-values.c +++ b/gcc/vr-values.c @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see #include "value-relation.h" #include "range-op.h" #include "gimple-range.h" +#include "gimple-range-fold.h" /* Set value range VR to a non-negative range of type TYPE. */ @@ -1230,7 +1231,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt) return; break; default: - if (range_of_builtin_call (*this, *vr, as_a (stmt))) + if (fold_range (*this, *vr, stmt)) { /* The original code nuked equivalences every time a range was found, so do the same here. */