commit 87f9ac937d6cfd81cbbe0a43518ba10781888d7c
Author: Andrew MacLeod <amacleod@redhat.com>
Date: Tue Jun 8 15:43:03 2021 -0400
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.
@@ -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);
+}
+
+// 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.
- // Finally must be on 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);