Virtualize fur_source and turn it into a proper API.

No more accessing the local info.  Also add fur_source/fold_stmt where ranges
are provided via being specified, or a vector to replace gimple_fold_range.

	* gimple-range-gori.cc (gori_compute::outgoing_edge_range_p): Use a
	fur_stmt source record.
	* gimple-range.cc (fur_source::get_operand): Generic range query.
	(fur_source::get_phi_operand): New.
	(fur_source::register_dependency): New.
	(fur_source::query): New.
	(class fur_edge): New.  Edge source for operands.
	(fur_edge::fur_edge): New.
	(fur_edge::get_operand): New.
	(fur_edge::get_phi_operand): New.
	(fur_edge::query): New.
	(fur_stmt::fur_stmt): New.
	(fur_stmt::get_operand): New.
	(fur_stmt::get_phi_operand): New.
	(fur_stmt::query): New.
	(class fur_depend): New.  Statement source and process dependencies.
	(fur_depend::fur_depend): New.
	(fur_depend::register_dependency): New.
	(class fur_list): New.  List source for operands.
	(fur_list::fur_list): New.
	(fur_list::get_operand): New.
	(fur_list::get_phi_operand): New.
	(fold_range): New.  Instantiate appropriate fur_source class and fold.
	(fold_using_range::range_of_range_op): Use new API.
	(fold_using_range::range_of_address): Ditto.
	(fold_using_range::range_of_phi): Ditto.
	(imple_ranger::fold_range_internal): Use fur_depend class.
	(fold_using_range::range_of_ssa_name_with_loop_info): Use new API.
	* gimple-range.h (class fur_source): Now a base class.
	(class fur_stmt): New.
	(fold_range): New prototypes.
	(fur_source::fur_source): Delete.
This commit is contained in:
Andrew MacLeod 2021-06-08 15:43:03 -04:00
parent 087253b995
commit 87f9ac937d
3 changed files with 315 additions and 102 deletions

View File

@ -1008,7 +1008,7 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
if (!stmt)
return false;
fur_source src (&q, NULL, e, stmt);
fur_stmt src (stmt, &q);
// If NAME can be calculated on the edge, use that.
if (is_export_p (name, e->src))

View File

@ -49,19 +49,284 @@ along with GCC; see the file COPYING3. If not see
// Evaluate expression EXPR using the source information the class was
// instantiated with. Place the result in R, and return TRUE. If a range
// cannot be calcluated, return FALSE.
// cannot be calculated, return FALSE.
bool
fur_source::get_operand (irange &r, tree expr)
{
// First look for a stmt.
if (m_stmt)
return m_query->range_of_expr (r, expr, m_stmt);
return get_range_query (cfun)->range_of_expr (r, expr);
}
// Finally must be on an edge.
// Evaluate EXPR for this stmt as a PHI argument on edge E. Use the current
// range_query to get the range on the edge.
bool
fur_source::get_phi_operand (irange &r, tree expr, edge e)
{
return get_range_query (cfun)->range_on_edge (r, e, expr);
}
// Default is to not register any dependencies from fold_using_range.
void
fur_source::register_dependency (tree lhs ATTRIBUTE_UNUSED,
tree rhs ATTRIBUTE_UNUSED)
{
}
// Default object is the current range query.
range_query *
fur_source::query ()
{
return get_range_query (cfun);
}
// This version of fur_source will pick a range up off an edge.
class fur_edge : public fur_source
{
public:
fur_edge (edge e, range_query *q = NULL);
virtual bool get_operand (irange &r, tree expr) OVERRIDE;
virtual bool get_phi_operand (irange &r, tree expr, edge e) OVERRIDE;
virtual range_query *query () OVERRIDE;
private:
range_query *m_query;
edge m_edge;
};
// Instantiate an edge based fur_source.
inline
fur_edge::fur_edge (edge e, range_query *q)
{
m_edge = e;
if (q)
m_query = q;
else
m_query = get_range_query (cfun);
}
// Get the value of EXPR on edge m_edge.
bool
fur_edge::get_operand (irange &r, tree expr)
{
return m_query->range_on_edge (r, m_edge, expr);
}
// Evaluate EXPR for this stmt as a PHI argument on edge E. Use the current
// range_query to get the range on the edge.
bool
fur_edge::get_phi_operand (irange &r, tree expr, edge e)
{
// edge to edge recalculations not supoprted yet, until we sort it out.
gcc_checking_assert (e == m_edge);
return m_query->range_on_edge (r, e, expr);
}
// Return the current range_query object.
range_query *
fur_edge::query ()
{
return m_query;
}
// Instantiate a stmt based fur_source.
fur_stmt::fur_stmt (gimple *s, range_query *q)
{
m_stmt= s;
if (q)
m_query = q;
else
m_query = get_global_range_query ();
}
// Retirenve range of EXPR as it occurs as a use on stmt M_STMT.
bool
fur_stmt::get_operand (irange &r, tree expr)
{
return m_query->range_of_expr (r, expr, m_stmt);
}
// Evaluate EXPR for this stmt as a PHI argument on edge E. Use the current
// range_query to get the range on the edge.
bool
fur_stmt::get_phi_operand (irange &r, tree expr, edge e)
{
// Pick up the range of expr from edge E.
fur_edge e_src (e, m_query);
return e_src.get_operand (r, expr);
}
// Return the current range_query object.
range_query *
fur_stmt::query ()
{
return m_query;
}
// This version of fur_source will pick a range from a stmt, and register
// also dependencies via a gori_compute object. This is mostly an internal API.
class fur_depend : public fur_stmt
{
public:
fur_depend (gimple *s, gori_compute *gori, range_query *q = NULL);
virtual void register_dependency (tree lhs, tree rhs) OVERRIDE;
private:
gori_compute *m_gori;
};
// Instantiate a stmt based fur_source witrh a GORI object
inline
fur_depend::fur_depend (gimple *s, gori_compute *gori, range_query *q)
: fur_stmt (s, q)
{
gcc_checking_assert (gori);
m_gori = gori;
}
// find and add any dependnecy between LHS and RHS
void
fur_depend::register_dependency (tree lhs, tree rhs)
{
m_gori->register_dependency (lhs, rhs);
}
// This version of fur_source will pick a range up from a list of ranges
// supplied by the caller.
class fur_list : public fur_source
{
public:
fur_list (irange &r1);
fur_list (irange &r1, irange &r2);
fur_list (unsigned num, irange *list);
virtual bool get_operand (irange &r, tree expr) OVERRIDE;
virtual bool get_phi_operand (irange &r, tree expr, edge e) OVERRIDE;
private:
int_range_max m_local[2];
irange *m_list;
unsigned m_index;
unsigned m_limit;
};
// One range supplied for unary operations.
fur_list::fur_list (irange &r1)
{
m_list = m_local;
m_index = 0;
m_limit = 1;
m_local[0] = r1;
}
// Two ranges supplied for binary operations.
fur_list::fur_list (irange &r1, irange &r2)
{
m_list = m_local;
m_index = 0;
m_limit = 2;
m_local[0] = r1;
m_local[0] = r2;
}
// Arbitrary number of ranges in a vector.
fur_list::fur_list (unsigned num, irange *list)
{
m_list = list;
m_index = 0;
m_limit = num;
}
// Get the next operand from the vector, ensure types are compatible,
bool
fur_list::get_operand (irange &r, tree expr)
{
if (m_index >= m_limit)
return get_range_query (cfun)->range_of_expr (r, expr);
r = m_list[m_index++];
gcc_checking_assert (range_compatible_p (TREE_TYPE (expr), r.type ()));
return true;
}
// This will simply pick the next operand from the vector.
bool
fur_list::get_phi_operand (irange &r, tree expr, edge e ATTRIBUTE_UNUSED)
{
return get_operand (r, expr);
}
// Fold stmt S into range R using R1 as the first operand.
bool
fold_range (irange &r, gimple *s, irange &r1)
{
fold_using_range f;
fur_list src (r1);
return f.fold_stmt (r, s, src);
}
// Fold stmt S into range R using R1 and R2 as the first two operands.
bool
fold_range (irange &r, gimple *s, irange &r1, irange &r2)
{
fold_using_range f;
fur_list src (r1, r2);
return f.fold_stmt (r, s, src);
}
// Fold stmt S into range R using NUM_ELEMENTS from VECTOR as the initial
// operands encountered.
bool
fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector)
{
fold_using_range f;
fur_list src (num_elements, vector);
return f.fold_stmt (r, s, src);
}
// Fold stmt S into range R using range query Q.
bool
fold_range (irange &r, gimple *s, range_query *q)
{
fold_using_range f;
fur_stmt src (s, q);
return f.fold_stmt (r, s, src);
}
// Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
bool
fold_range (irange &r, gimple *s, edge on_edge, range_query *q)
{
fold_using_range f;
fur_edge src (on_edge, q);
return f.fold_stmt (r, s, src);
}
// -------------------------------------------------------------------------
// Adjust the range for a pointer difference where the operands came
// from a memchr.
@ -375,17 +640,17 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
// Fold range, and register any dependency if available.
int_range<2> r2 (type);
handler->fold_range (r, type, range1, r2);
if (lhs && src.m_gori)
src.m_gori->register_dependency (lhs, op1);
if (lhs)
src.register_dependency (lhs, op1);
}
else if (src.get_operand (range2, op2))
{
// Fold range, and register any dependency if available.
handler->fold_range (r, type, range1, range2);
if (lhs && src.m_gori)
if (lhs)
{
src.m_gori->register_dependency (lhs, op1);
src.m_gori->register_dependency (lhs, op2);
src.register_dependency (lhs, op1);
src.register_dependency (lhs, op2);
}
}
else
@ -425,8 +690,8 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
{
tree ssa = TREE_OPERAND (base, 0);
tree lhs = gimple_get_lhs (stmt);
if (src.m_gori && lhs && gimple_range_ssa_p (ssa))
src.m_gori->register_dependency (lhs, ssa);
if (lhs && gimple_range_ssa_p (ssa))
src.register_dependency (lhs, ssa);
gcc_checking_assert (irange::supports_type_p (TREE_TYPE (ssa)));
src.get_operand (r, ssa);
range_cast (r, TREE_TYPE (gimple_assign_rhs1 (stmt)));
@ -503,19 +768,12 @@ fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src)
edge e = gimple_phi_arg_edge (phi, x);
// Register potential dependencies for stale value tracking.
if (src.m_gori && gimple_range_ssa_p (arg))
src.m_gori->register_dependency (phi_def, arg);
if (gimple_range_ssa_p (arg))
src.register_dependency (phi_def, arg);
// Get the range of the argument on its edge.
fur_source e_src (src.m_query, e);
e_src.get_operand (arg_range, arg);
src.get_phi_operand (arg_range, arg, e);
// If we're recomputing the argument elsewhere, try to refine it.
if (src.m_stmt != phi)
{
int_range_max tmp;
e_src.get_operand (tmp, arg);
arg_range.intersect (tmp);
}
r.union_ (arg_range);
// Once the value reaches varying, stop looking.
if (r.varying_p ())
@ -1012,7 +1270,7 @@ bool
gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name)
{
fold_using_range f;
fur_source src (this, &(gori ()), NULL, s);
fur_depend src (s, &(gori ()), this);
return f.fold_stmt (r, s, src, name);
}
@ -1191,22 +1449,18 @@ fold_using_range::range_of_ssa_name_with_loop_info (irange &r, tree name,
{
gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
tree min, max, type = TREE_TYPE (name);
if (bounds_of_var_in_loop (&min, &max, src.m_query, l, phi, name))
if (bounds_of_var_in_loop (&min, &max, src.query (), l, phi, name))
{
if (TREE_CODE (min) != INTEGER_CST)
{
if (src.m_query
&& src.m_query->range_of_expr (r, min, phi)
&& !r.undefined_p ())
if (src.query ()->range_of_expr (r, min, phi) && !r.undefined_p ())
min = wide_int_to_tree (type, r.lower_bound ());
else
min = vrp_val_min (type);
}
if (TREE_CODE (max) != INTEGER_CST)
{
if (src.m_query
&& src.m_query->range_of_expr (r, max, phi)
&& !r.undefined_p ())
if (src.query ()->range_of_expr (r, max, phi) && !r.undefined_p ())
max = wide_int_to_tree (type, r.upper_bound ());
else
max = vrp_val_max (type);

View File

@ -73,28 +73,45 @@ protected:
ranger_cache m_cache;
};
// Source of an operand for fold_using_range.
// It can specify a stmt or and edge, or thru an internal API which uses
// the ranger cache.
// Its primary function is to retreive an operand from the source via a
// call thru the range_query object.
// Source of all operands for fold_using_range and gori_compute.
// It abstracts out the source of an operand so it can come from a stmt or
// and edge or anywhere a derived classof fur_source wants.
class fur_source
{
friend class fold_using_range;
public:
inline fur_source (range_query *q, edge e);
inline fur_source (range_query *q, gimple *s);
inline fur_source (range_query *q, gori_compute *g, edge e, gimple *s);
bool get_operand (irange &r, tree expr);
protected:
gori_compute *m_gori;
virtual bool get_operand (irange &r, tree expr);
virtual bool get_phi_operand (irange &r, tree expr, edge e);
virtual void register_dependency (tree lhs, tree rhs);
virtual range_query *query ();
};
// fur_stmt is the specification for drawing an operand from range_query Q
// via a range_of_Expr call on stmt S.
class fur_stmt : public fur_source
{
public:
fur_stmt (gimple *s, range_query *q = NULL);
virtual bool get_operand (irange &r, tree expr) OVERRIDE;
virtual bool get_phi_operand (irange &r, tree expr, edge e) OVERRIDE;
virtual range_query *query () OVERRIDE;
private:
range_query *m_query;
edge m_edge;
gimple *m_stmt;
};
// Fold stmt S into range R using range query Q.
bool fold_range (irange &r, gimple *s, range_query *q = NULL);
// Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
bool fold_range (irange &r, gimple *s, edge on_edge, range_query *q = NULL);
// These routines allow you to specify the operands to use when folding.
// Any excess queries will be drawn from the current range_query.
bool fold_range (irange &r, gimple *s, irange &r1);
bool fold_range (irange &r, gimple *s, irange &r1, irange &r2);
bool fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector);
// This class uses ranges to fold a gimple statement producinf a range for
// the LHS. The source of all operands is supplied via the fur_source class
// which provides a range_query as well as a source location and any other
@ -119,64 +136,6 @@ protected:
};
// Create a source for a query on an edge.
inline
fur_source::fur_source (range_query *q, edge e)
{
m_query = q;
m_gori = NULL;
m_edge = e;
m_stmt = NULL;
}
// Create a source for a query at a statement.
inline
fur_source::fur_source (range_query *q, gimple *s)
{
m_query = q;
m_gori = NULL;
m_edge = NULL;
m_stmt = s;
}
// Create a source for Ranger. THis can recalculate from a different location
// and can also set the dependency information as appropriate when invoked.
inline
fur_source::fur_source (range_query *q, gori_compute *g, edge e, gimple *s)
{
m_query = q;
m_gori = g;
m_edge = e;
m_stmt = s;
}
// Fold stmt S into range R using range query Q.
inline bool
fold_range (irange &r, gimple *s, range_query *q = NULL)
{
fold_using_range f;
if (q == NULL)
q = get_global_range_query ();
fur_source src (q, s);
return f.fold_stmt (r, s, src);
}
// Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
inline bool
fold_range (irange &r, gimple *s, edge on_edge, range_query *q = NULL)
{
fold_using_range f;
if (q == NULL)
q = get_global_range_query ();
fur_source src (q, on_edge);
return f.fold_stmt (r, s, src);
}
// These routines provide a GIMPLE interface to the range-ops code.
extern tree gimple_range_operand1 (const gimple *s);
extern tree gimple_range_operand2 (const gimple *s);