mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-14 14:33:40 +08:00
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:
parent
087253b995
commit
87f9ac937d
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user