// 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);
}
// 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);
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);
}
}
// 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);
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))
// 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
// 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);
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
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);
}
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; }