https://gcc.gnu.org/g:faddf22942884a4c951ca0eeffc364296378eeff
commit r15-5999-gfaddf22942884a4c951ca0eeffc364296378eeff Author: Andrew MacLeod <amacl...@redhat.com> Date: Sat Nov 16 08:29:30 2024 -0500 Add a range query to inferred ranges. Provide a range_query for any inferred range processing which wants to examine the range of an argument to make decisions. Add some comments. * gimple-range-cache.cc (ranger_cache::ranger_cache): Create the infer oracle using THIS as the range_query. * gimple-range-infer.cc (gimple_infer_range::gimple_infer_range): Add a range_query to the constructor and use it. (infer_range_manager::infer_range_manager): Add a range_query. * gimple-range-infer.h (gimple_infer_range): Adjust prototype. (infer_range_manager): Add a range_query. * value-query.cc (range_query::create_infer_oracle): Add a range_query. * value-query.h (range_query::create_infer_oracle): Update prototype. Diff: --- gcc/gimple-range-cache.cc | 5 ++++- gcc/gimple-range-infer.cc | 24 ++++++++++++++++------- gcc/gimple-range-infer.h | 50 +++++++++++++++++++++++++++++++++++++++++------ gcc/value-query.cc | 10 ++++++++-- gcc/value-query.h | 2 +- 5 files changed, 74 insertions(+), 17 deletions(-) diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index c9016fe988db..489b12163008 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -1002,7 +1002,10 @@ ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses) // If DOM info is available, spawn an oracle as well. create_relation_oracle (); - create_infer_oracle (use_imm_uses); + // Create an infer oracle using this cache as the range query. The cache + // version acts as a read-only query, and will spawn no additional lookups. + // It just ues what is already known. + create_infer_oracle (this, use_imm_uses); create_gori (not_executable_flag, param_vrp_switch_limit); unsigned x, lim = last_basic_block_for_fn (cfun); diff --git a/gcc/gimple-range-infer.cc b/gcc/gimple-range-infer.cc index b5621f0b22aa..aba5c3d9bfcb 100644 --- a/gcc/gimple-range-infer.cc +++ b/gcc/gimple-range-infer.cc @@ -151,19 +151,24 @@ gimple_infer_range::add_nonzero (tree name) } // Process S for range inference and fill in the summary list. -// This is the routine where new inferred ranges should be added. +// This is the routine where any new inferred ranges should be added. // If USE_RANGEOPS is true, invoke range-ops on stmts with a single -// ssa-name aa constant to reflect an inferred range. ie +// ssa-name a constant to reflect an inferred range. ie // x_2 = y_3 + 1 will provide an inferred range for y_3 of [-INF, +INF - 1]. // This defaults to FALSE as it can be expensive., -gimple_infer_range::gimple_infer_range (gimple *s, bool use_rangeops) +gimple_infer_range::gimple_infer_range (gimple *s, range_query *q, + bool use_rangeops) { num_args = 0; if (is_a<gphi *> (s)) return; + // Default to the global query if none provided. + if (!q) + q = get_global_range_query (); + if (is_a<gcall *> (s) && flag_delete_null_pointer_checks) { tree fntype = gimple_call_fntype (s); @@ -243,14 +248,14 @@ gimple_infer_range::gimple_infer_range (gimple *s, bool use_rangeops) if (ssa1) { value_range op1 (TREE_TYPE (ssa1)); - if (op1_range (op1, s, get_global_range_query ()) && !op1.varying_p ()) + if (op1_range (op1, s, q) && !op1.varying_p ()) add_range (ssa1, op1); } else { gcc_checking_assert (ssa2); value_range op2 (TREE_TYPE (ssa2)); - if (op2_range (op2, s, get_global_range_query ()) && !op2.varying_p ()) + if (op2_range (op2, s, q) && !op2.varying_p ()) add_range (ssa2, op2); } } @@ -297,9 +302,14 @@ infer_range_manager::exit_range_head::find_ptr (tree ssa) // Construct a range infer manager. DO_SEARCH indicates whether an immediate // use scan should be made the first time a name is processed. This is for // on-demand clients who may not visit every statement and may miss uses. +// Q is the range_query to use for any lookups. Default is NULL which maps +// to the global_range_query. -infer_range_manager::infer_range_manager (bool do_search) +infer_range_manager::infer_range_manager (bool do_search, range_query *q) { + // Set the range query to use. + m_query = q ? q : get_global_range_query (); + bitmap_obstack_initialize (&m_bitmaps); m_on_exit.create (0); m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); @@ -473,7 +483,7 @@ infer_range_manager::register_all_uses (tree name) FOR_EACH_IMM_USE_FAST (use_p, iter, name) { gimple *s = USE_STMT (use_p); - gimple_infer_range infer (s); + gimple_infer_range infer (s, m_query); for (unsigned x = 0; x < infer.num (); x++) { if (name == infer.name (x)) diff --git a/gcc/gimple-range-infer.h b/gcc/gimple-range-infer.h index b11d28352adf..049ce78cab2e 100644 --- a/gcc/gimple-range-infer.h +++ b/gcc/gimple-range-infer.h @@ -27,11 +27,39 @@ along with GCC; see the file COPYING3. If not see // This class manages an on-demand summary of inferred ranges for a statement. // It can be instantiated as required and provides a list of inferred ranges. // New inferred ranges should be added in the constructor of this class. +// +// There are 2 main instantiations. +// gimple_range_infer (gimple *s, range_query *q, bool use_range_ops) +// S is the statement being queried. +// Q is a range-query object which is used to resolve any ranges that +// might be required. This defaults to NULL which maps to the +// global_range_query, which is what most passes will want. +// Ranger internally will pass the cache's range-query which is a +// read-only query and prevents any additional lookup. +// USE_RANGEOPS is a boolean flag which defaults to false. if TRUE, +// range-ops is invoked to see if any additional side effects are seen +// based on the stmt. ie .x = y * 2 will reigster a side effect for Y +// which is [-INF/2 , +INF/2]. It is not on by default because it +// is a relatively expensive operation to do on every statement, and +// ranger will already incorporate that range for Y via GORI most of the +// time that it matters. Individual passes may have use for it however. +// PR 113879 is an example where this can be of use. +// +// gimple_range_infer (tree name, vrange &r) +// This instantiation simply create an inferred range record directly. +// NAME is the SSA_NAME to create the record for +// R is the range for NAME. +// +// Once a gimple_infer_range record has been created, the API is simple: +// num () - The number of inferred ranges in this record. +// name (i) - The i'th SSA_NAME in this record. +// range (i) - The range of the i'th SSA_NAME. class gimple_infer_range { public: - gimple_infer_range (gimple *s, bool use_rangeops = false); + gimple_infer_range (gimple *s, range_query *q = NULL, + bool use_rangeops = false); gimple_infer_range (tree name, vrange &r); inline unsigned num () const { return num_args; } inline tree name (unsigned index) const @@ -65,14 +93,24 @@ public: // This class manages a list of inferred ranges for each basic block. // As inferences are made, they can be registered to a block and later -// queried. When constructed with a TRUE flag, immediate uses chains are -// followed the first time a name is referenced and block populated if -// there are any inferred ranges. +// queried via a DOM search. +// When DO_SEARCH is TRUE, immediate uses chains are followed the first time +// a name is referenced and block populated if there are any inferred ranges. +// range_query Q is the range_query to use for any range lookups. It defaults +// to NULL which maps to the global_range_query. This is what most passes +// will want to use. Ranger invokes it with the cache's internal query which +// can provide better ranges during a DOM walk. +// +// add_ranges is used to add inferred range IR assocaited with stmt S. +// has_range_p is used to check if NAME has an inferred range in block BB. +// maybe_adjust_range will adjust the range R to incorporate any inferred +// range NAME may have in block BB. If there are on inferred ranges in +// block BB, then R will be unchanged, otherwise the ranges are intersected. class infer_range_manager : public infer_range_oracle { public: - infer_range_manager (bool do_search); + infer_range_manager (bool do_search, range_query *q = NULL); virtual ~infer_range_manager (); virtual void add_ranges (gimple *s, gimple_infer_range &ir); virtual bool has_range_p (basic_block bb, tree name = NULL_TREE); @@ -96,6 +134,6 @@ private: bitmap_obstack m_bitmaps; struct obstack m_list_obstack; class vrange_allocator *m_range_allocator; + range_query *m_query; }; - #endif // GCC_GIMPLE_RANGE_SIDE_H diff --git a/gcc/value-query.cc b/gcc/value-query.cc index 34499da1a987..0723d19a1939 100644 --- a/gcc/value-query.cc +++ b/gcc/value-query.cc @@ -206,11 +206,17 @@ range_query::destroy_gori () m_gori= &default_gori; } +// Create an infer oracle using Q as the default range query if needed. +// if DO_SEARCH is true, use immediate uses to scan alluses of a NAME the first +// time it is queried. This is primarily for passes which operate in the +// on-demand model where earlier uses may not have been seen. +// VRP and DOM walk passes set this to FALSE as they will walk all statements +// in order. void -range_query::create_infer_oracle (bool do_search) +range_query::create_infer_oracle (range_query *q, bool do_search) { gcc_checking_assert (m_infer == &default_infer_oracle); - m_infer = new infer_range_manager (do_search); + m_infer = new infer_range_manager (do_search, q); gcc_checking_assert (m_infer); } diff --git a/gcc/value-query.h b/gcc/value-query.h index 78840fd7a783..07e63b8ac940 100644 --- a/gcc/value-query.h +++ b/gcc/value-query.h @@ -80,7 +80,7 @@ public: void destroy_relation_oracle (); inline class infer_range_oracle &infer_oracle () const { return *m_infer; } - void create_infer_oracle (bool do_search = TRUE); + void create_infer_oracle (range_query *q = NULL, bool do_search = true); void destroy_infer_oracle (); inline class gimple_outgoing_range &gori () const { return *m_gori; }