aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-range.cc
diff options
context:
space:
mode:
authorAldy Hernandez <aldyh@redhat.com>2021-05-19 18:27:05 +0200
committerAldy Hernandez <aldyh@redhat.com>2021-05-26 21:26:54 +0200
commit586d6f7aee0ba9faf3d9b7afd6ff89d57763a775 (patch)
tree42a7e51305d494dc2209159686571148982a0be7 /gcc/gimple-range.cc
parent28484d00c45b7bf094a22a4fddf9ffdc7482c7e1 (diff)
downloadgcc-586d6f7aee0ba9faf3d9b7afd6ff89d57763a775.zip
gcc-586d6f7aee0ba9faf3d9b7afd6ff89d57763a775.tar.gz
gcc-586d6f7aee0ba9faf3d9b7afd6ff89d57763a775.tar.bz2
Common API for accessing global and on-demand ranges.
This patch provides a generic API for accessing global ranges. It is meant to replace get_range_info() and get_ptr_nonnull() with one common interface. It uses the same API as the ranger (class range_query), so there will now be one API for accessing local and global ranges alike. Follow-up patches will convert all users of get_range_info and get_ptr_nonnull to this API. For get_range_info, instead of: if (!POINTER_TYPE_P (TREE_TYPE (name)) && SSA_NAME_RANGE_INFO (name)) get_range_info (name, vr); You can now do: get_range_query (cfun)->range_of_expr (vr, name, [stmt]); ...as well as any other of the range_query methods (range_on_edge, range_of_stmt, value_of_expr, value_on_edge, value_on_stmt, etc). As per the API, range_of_expr will work on constants, SSA names, and anything we support in irange::supports_type_p(). For pointers, the interface is the same, so instead of: else if (POINTER_TYPE_P (TREE_TYPE (name)) && SSA_NAME_PTR_INFO (name)) { if (get_ptr_nonnull (name)) stuff(); } One can do: get_range_query (cfun)->range_of_expr (vr, name, [stmt]); if (vr.nonzero_p ()) stuff (); Along with this interface, we are providing a mechanism by which a pass can use an on-demand ranger transparently, without having to change its code. Of course, this assumes all get_range_info() and get_ptr_nonnull() users have been converted to the new API, which follow-up patches will do. If a pass would prefer to use an on-demand ranger with finer grained and context aware ranges, all it would have to do is call enable_ranger() at the beginning of the pass, and disable_ranger() at the end of the pass. Note, that to use context aware ranges, any user of range_of_expr() would need to pass additional context. For example, the optional gimple statement (or perhaps use range_on_edge or range_of_stmt). The observant reader will note that get_range_query is tied to a struct function, which may not be available in certain contexts, such as at RTL time, gimple-fold, or some other places where we may or may not have cfun set. For cases where we are sure there is no function, you can use get_global_range_query() instead of get_range_query(fun). The API is the same. For cases where a function may be called with or without a function, you could use the following idiom: range_query *query = cfun ? get_range_query (cfun) : get_global_range_query (); query->range_of_expr (range, expr, [stmt]); The default range query obtained by get_range_query() is the global range query, unless the user has enabled an on-demand ranger with enable_ranger(), in which case it will use the currently active ranger. That is, until disable_ranger() is called, at which point, we revert back to global ranges. We think this provides a generic way of accessing ranges, both globally and locally, without having to keep track of types, SSA_NAME_RANGE_INFO, and SSA_NAME_PTR_INFO. We also hope this can be used to transition passes from global to on-demand ranges when appropriate. gcc/ChangeLog: * function.c (allocate_struct_function): Set cfun->x_range_query. * function.h (struct function): Declare x_range_query. (get_range_query): New. (get_global_range_query): New. * gimple-range-cache.cc (ssa_global_cache::ssa_global_cache): Remove call to safe_grow_cleared. * gimple-range.cc (get_range_global): New. (gimple_range_global): Move from gimple-range.h. (get_global_range_query): New. (global_range_query::range_of_expr): New. (enable_ranger): New. (disable_ranger): New. * gimple-range.h (gimple_range_global): Move to gimple-range.cc. (class global_range_query): New. (enable_ranger): New. (disable_ranger): New. * gimple-ssa-evrp.c (evrp_folder::~evrp_folder): Rename dump_all_value_ranges to dump. * tree-vrp.c (vrp_prop::finalize): Same. * value-query.cc (range_query::dump): New. * value-query.h (range_query::dump): New. * vr-values.c (vr_values::dump_all_value_ranges): Rename to... (vr_values::dump): ...this. * vr-values.h (class vr_values): Rename dump_all_value_ranges to dump and make virtual.
Diffstat (limited to 'gcc/gimple-range.cc')
-rw-r--r--gcc/gimple-range.cc126
1 files changed, 126 insertions, 0 deletions
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index e2d24d6..e351a84 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -1440,3 +1440,129 @@ trace_ranger::range_of_expr (irange &r, tree name, gimple *s)
return trailer (idx, "range_of_expr", res, name, r);
}
+
+// Return the legacy global range for NAME if it has one, otherwise
+// return VARYING.
+
+static void
+get_range_global (irange &r, tree name)
+{
+ tree type = TREE_TYPE (name);
+
+ if (SSA_NAME_IS_DEFAULT_DEF (name))
+ {
+ tree sym = SSA_NAME_VAR (name);
+ // Adapted from vr_values::get_lattice_entry().
+ // Use a range from an SSA_NAME's available range.
+ if (TREE_CODE (sym) == PARM_DECL)
+ {
+ // Try to use the "nonnull" attribute to create ~[0, 0]
+ // anti-ranges for pointers. Note that this is only valid with
+ // default definitions of PARM_DECLs.
+ if (POINTER_TYPE_P (type)
+ && ((cfun && nonnull_arg_p (sym)) || get_ptr_nonnull (name)))
+ r.set_nonzero (type);
+ else if (INTEGRAL_TYPE_P (type))
+ {
+ get_range_info (name, r);
+ if (r.undefined_p ())
+ r.set_varying (type);
+ }
+ else
+ r.set_varying (type);
+ }
+ // If this is a local automatic with no definition, use undefined.
+ else if (TREE_CODE (sym) != RESULT_DECL)
+ r.set_undefined ();
+ else
+ r.set_varying (type);
+ }
+ else if (!POINTER_TYPE_P (type) && SSA_NAME_RANGE_INFO (name))
+ {
+ get_range_info (name, r);
+ if (r.undefined_p ())
+ r.set_varying (type);
+ }
+ else if (POINTER_TYPE_P (type) && SSA_NAME_PTR_INFO (name))
+ {
+ if (get_ptr_nonnull (name))
+ r.set_nonzero (type);
+ else
+ r.set_varying (type);
+ }
+ else
+ r.set_varying (type);
+}
+
+// ?? Like above, but only for default definitions of NAME. This is
+// so VRP passes using ranger do not start with known ranges,
+// otherwise we'd eliminate builtin_unreachables too early because of
+// inlining.
+//
+// Without this restriction, the test in g++.dg/tree-ssa/pr61034.C has
+// all of its unreachable calls removed too early. We should
+// investigate whether we should just adjust the test above.
+
+value_range
+gimple_range_global (tree name)
+{
+ gcc_checking_assert (gimple_range_ssa_p (name));
+ tree type = TREE_TYPE (name);
+
+ if (SSA_NAME_IS_DEFAULT_DEF (name))
+ {
+ value_range vr;
+ get_range_global (vr, name);
+ return vr;
+ }
+ return value_range (type);
+}
+
+// ----------------------------------------------
+// global_range_query implementation.
+
+global_range_query global_ranges;
+
+// Like get_range_query, but for accessing global ranges.
+
+range_query *
+get_global_range_query ()
+{
+ return &global_ranges;
+}
+
+bool
+global_range_query::range_of_expr (irange &r, tree expr, gimple *)
+{
+ tree type = TREE_TYPE (expr);
+
+ if (!irange::supports_type_p (type) || !gimple_range_ssa_p (expr))
+ return get_tree_range (r, expr);
+
+ get_range_global (r, expr);
+
+ return true;
+}
+
+gimple_ranger *
+enable_ranger (struct function *fun)
+{
+ gimple_ranger *r;
+
+ if (param_evrp_mode & EVRP_MODE_TRACE)
+ r = new trace_ranger;
+ else
+ r = new gimple_ranger;
+
+ fun->x_range_query = r;
+
+ return r;
+}
+
+void
+disable_ranger (struct function *fun)
+{
+ delete fun->x_range_query;
+
+ fun->x_range_query = &global_ranges;
+}