From f163826f0e2b266c668e1500b3feb9a210569a0d Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Tue, 18 Oct 2022 16:30:04 -0400 Subject: [PATCH 2/3] assume_query support --- gcc/gimple-range-gori.h | 6 +- gcc/gimple-range.cc | 161 ++++++++++++++++++++++++++++++++++++++++ gcc/gimple-range.h | 17 +++++ 3 files changed, 181 insertions(+), 3 deletions(-) diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h index c7a32162a1b..6cc533b58b2 100644 --- a/gcc/gimple-range-gori.h +++ b/gcc/gimple-range-gori.h @@ -165,15 +165,15 @@ public: bool has_edge_range_p (tree name, basic_block bb = NULL); bool has_edge_range_p (tree name, edge e); void dump (FILE *f); + bool compute_operand_range (vrange &r, gimple *stmt, const vrange &lhs, + tree name, class fur_source &src, + value_relation *rel = NULL); private: bool refine_using_relation (tree op1, vrange &op1_range, tree op2, vrange &op2_range, fur_source &src, relation_kind k); bool may_recompute_p (tree name, edge e); bool may_recompute_p (tree name, basic_block bb = NULL); - bool compute_operand_range (vrange &r, gimple *stmt, const vrange &lhs, - tree name, class fur_source &src, - value_relation *rel = NULL); bool compute_operand_range_switch (vrange &r, gswitch *s, const vrange &lhs, tree name, fur_source &src); bool compute_operand1_range (vrange &r, gimple_range_op_handler &handler, diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index d67d6499c78..0990c1ca01e 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -645,3 +645,164 @@ disable_ranger (struct function *fun) delete fun->x_range_query; fun->x_range_query = NULL; } + +// ------------------------------------------------------------------------ + +// If there is a non-varying value associated with NAME, return true and the +// range in R. + +bool +assume_query::assume_range_p (vrange &r, tree name) +{ + if (global.get_global_range (r, name)) + return !r.varying_p (); + return false; +} + +// Query used by GORI to pick up any known value on entry to a block. + +bool +assume_query::range_of_expr (vrange &r, tree expr, gimple *stmt) +{ + if (!gimple_range_ssa_p (expr)) + return get_tree_range (r, expr, stmt); + + if (!global.get_global_range (r, expr)) + r.set_varying (TREE_TYPE (expr)); + return true; +} + +// If the current function returns an integral value, and has a single return +// statement, it will calculate any SSA_NAMES is can determine ranges forr +// assuming the function returns 1. + +assume_query::assume_query () +{ + basic_block exit_bb = EXIT_BLOCK_PTR_FOR_FN (cfun); + if (single_pred_p (exit_bb)) + { + basic_block bb = single_pred (exit_bb); + gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb); + if (gsi_end_p (gsi)) + return; + gimple *s = gsi_stmt (gsi); + if (!is_a (s)) + return; + greturn *gret = as_a (s); + tree op = gimple_return_retval (gret); + if (!gimple_range_ssa_p (op)) + return; + tree lhs_type = TREE_TYPE (op); + if (!irange::supports_p (lhs_type)) + return; + + unsigned prec = TYPE_PRECISION (lhs_type); + int_range<2> lhs_range (lhs_type, wi::one (prec), wi::one (prec)); + global.set_global_range (op, lhs_range); + + gimple *def = SSA_NAME_DEF_STMT (op); + if (!def || gimple_get_lhs (def) != op) + return; + fur_stmt src (gret, this); + calculate_stmt (def, lhs_range, src); + } +} + +// Evaluate operand OP on statement S, using the provided LHS range. +// If successful, set the range in the global table, then visit OP's def stmt. + +void +assume_query::calculate_op (tree op, gimple *s, vrange &lhs, fur_source &src) +{ + Value_Range op_range (TREE_TYPE (op)); + if (!global.get_global_range (op_range, op) + && m_gori.compute_operand_range (op_range, s, lhs, op, src) + && !op_range.varying_p ()) + { + global.set_global_range (op, op_range); + gimple *def_stmt = SSA_NAME_DEF_STMT (op); + if (def_stmt && gimple_get_lhs (def_stmt) == op) + calculate_stmt (def_stmt, op_range, src); + } +} + +// Evaluate PHI statement, using the provided LHS range. +// Check each constant argument predecessor if it can be taken +// provide LHS to any symbolic argmeuents, and process their def statements. + +void +assume_query::calculate_phi (gphi *phi, vrange &lhs_range, fur_source &src) +{ + for (unsigned x= 0; x < gimple_phi_num_args (phi); x++) + { + tree arg = gimple_phi_arg_def (phi, x); + Value_Range arg_range (TREE_TYPE (arg)); + if (gimple_range_ssa_p (arg)) + { + // A symbol arg will be the LHS value. + arg_range = lhs_range; + range_cast (arg_range, TREE_TYPE (arg)); + if (!global.get_global_range (arg_range, arg)) + { + global.set_global_range (arg, arg_range); + gimple *def_stmt = SSA_NAME_DEF_STMT (arg); + if (def_stmt && gimple_get_lhs (def_stmt) == arg) + calculate_stmt (def_stmt, arg_range, src); + } + } + else if (get_tree_range (arg_range, arg, NULL)) + { + // If this is a constant value that differs from LHS, this + // edge cannot be taken. + arg_range.intersect (lhs_range); + if (arg_range.undefined_p ()) + continue; + // Otherwise check the condition feeding this edge. + edge e = gimple_phi_arg_edge (phi, x); + check_taken_edge (e, src); + } + } +} + +// If an edge is known to be taken, examine the outgoing edge to see +// if it carries any range information that can also be evaluated. + +void +assume_query::check_taken_edge (edge e, fur_source &src) +{ + gimple *stmt = gimple_outgoing_range_stmt_p (e->src); + if (stmt && is_a (stmt)) + { + int_range<2> cond; + gcond_edge_range (cond, e); + calculate_stmt (stmt, cond, src); + } +} + +// Evaluate statement S which produces range LHS_RANGE. + +void +assume_query::calculate_stmt (gimple *s, vrange &lhs_range, fur_source &src) +{ + gimple_range_op_handler handler (s); + if (handler) + { + tree op = gimple_range_ssa_p (handler.operand1 ()); + if (op) + calculate_op (op, s, lhs_range, src); + op = gimple_range_ssa_p (handler.operand2 ()); + if (op) + calculate_op (op, s, lhs_range, src); + } + else if (is_a (s)) + { + calculate_phi (as_a (s), lhs_range, src); + // Don't further check predecessors of blocks with PHIs. + return; + } + + // Even if the walk back terminates before the top, if this is a single + // predecessor block, see if the predecessor provided any ranges to get here. + if (single_pred_p (gimple_bb (s))) + check_taken_edge (single_pred_edge (gimple_bb (s)), src); +} diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index 8b2ff5685e5..4dc7bc33c5f 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -80,4 +80,21 @@ extern gimple_ranger *enable_ranger (struct function *m, bool use_imm_uses = true); extern void disable_ranger (struct function *); +class assume_query : public range_query +{ +public: + assume_query (); + bool assume_range_p (vrange &r, tree name); + virtual bool range_of_expr (vrange &r, tree expr, gimple * = NULL); +protected: + void calculate_stmt (gimple *s, vrange &lhs_range, fur_source &src); + void calculate_op (tree op, gimple *s, vrange &lhs, fur_source &src); + void calculate_phi (gphi *phi, vrange &lhs_range, fur_source &src); + void check_taken_edge (edge e, fur_source &src); + + ssa_global_cache global; + gori_compute m_gori; +}; + + #endif // GCC_GIMPLE_RANGE_H -- 2.37.3