]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Common API for accessing global and on-demand ranges.
authorAldy Hernandez <aldyh@redhat.com>
Wed, 19 May 2021 16:27:05 +0000 (18:27 +0200)
committerAldy Hernandez <aldyh@redhat.com>
Wed, 26 May 2021 19:26:54 +0000 (21:26 +0200)
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.

gcc/function.c
gcc/function.h
gcc/gimple-range-cache.cc
gcc/gimple-range.cc
gcc/gimple-range.h
gcc/gimple-ssa-evrp.c
gcc/tree-vrp.c
gcc/value-query.cc
gcc/value-query.h
gcc/vr-values.c
gcc/vr-values.h

index fc7b147b5f1b0109114a202826d4ef677471097f..675769509832c4ef937cfa6410cba8f0b5f48ec3 100644 (file)
@@ -82,6 +82,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "options.h"
 #include "function-abi.h"
+#include "value-range.h"
+#include "gimple-range.h"
 
 /* So we can assign to cfun in this file.  */
 #undef cfun
@@ -4856,6 +4858,8 @@ allocate_struct_function (tree fndecl, bool abstract_p)
      binding annotations among them.  */
   cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
     && MAY_HAVE_DEBUG_MARKER_STMTS;
+
+  cfun->x_range_query = &global_ranges;
 }
 
 /* This is like allocate_struct_function, but pushes a new cfun for FNDECL
index 66cfa9738081e5017d2079ed7553aa5794b3f46c..0db51775e7c68732ed42d0edd9cab4065d690ab6 100644 (file)
@@ -157,6 +157,7 @@ struct GTY(()) rtl_eh {
 struct gimple_df;
 struct call_site_record_d;
 struct dw_fde_node;
+class range_query;
 
 struct GTY(()) varasm_status {
   /* If we're using a per-function constant pool, this is it.  */
@@ -309,6 +310,11 @@ struct GTY(()) function {
      debugging is enabled.  */
   struct dw_fde_node *fde;
 
+  /* Range query mechanism for functions.  The default is to pick up
+     global ranges.  If a pass wants on-demand ranges OTOH, it must
+     call enable/disable_ranger().  */
+  range_query * GTY ((skip)) x_range_query;
+
   /* Last statement uid.  */
   int last_stmt_uid;
 
@@ -712,4 +718,15 @@ extern const char *current_function_name (void);
 
 extern void used_types_insert (tree);
 
+/* Returns the currently active range access class.  When there is no active
+   range class, global ranges are used.  */
+
+inline range_query *
+get_range_query (struct function *fun)
+{
+  return fun->x_range_query;
+}
+
+extern range_query *get_global_range_query ();
+
 #endif  /* GCC_FUNCTION_H */
index 3969c4de220aab6b04ce3b59ac69053fab1c3636..889cac1ea65d3bced4f1011eb71adadd30e192ca 100644 (file)
@@ -384,7 +384,6 @@ block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
 ssa_global_cache::ssa_global_cache ()
 {
   m_tab.create (0);
-  m_tab.safe_grow_cleared (num_ssa_names);
   m_irange_allocator = new irange_allocator;
 }
 
index e2d24d6e45186dc09fe7baa211e643e553c9f0b0..e351a841583953c302cba9ba5fd0f5960ae8abdb 100644 (file)
@@ -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;
+}
index 707dcfe027be34ca7fe038c45087f9227dd01e57..23734c6e226114a5f754095c46431ea5cd64daf2 100644 (file)
@@ -65,7 +65,7 @@ public:
   virtual void range_on_entry (irange &r, basic_block bb, tree name);
   virtual void range_on_exit (irange &r, basic_block bb, tree name);
   void export_global_ranges ();
-  void dump (FILE *f);
+  virtual void dump (FILE *f) OVERRIDE;
   void dump_bb (FILE *f, basic_block bb);
 protected:
   bool fold_range_internal (irange &r, gimple *s, tree name);
@@ -227,50 +227,6 @@ range_compatible_p (tree type1, tree type2)
          && TYPE_SIGN (type1) == TYPE_SIGN (type2));
 }
 
-// Return the legacy GCC global range for NAME if it has one, otherwise
-// return VARYING.
-
-static inline 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))
-    {
-      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)
-             && (nonnull_arg_p (sym) || get_ptr_nonnull (name)))
-           {
-             value_range r;
-             r.set_nonzero (type);
-             return r;
-           }
-         else if (INTEGRAL_TYPE_P (type))
-           {
-             value_range r;
-             get_range_info (name, r);
-             if (r.undefined_p ())
-               r.set_varying (type);
-             return r;
-           }
-       }
-      // If this is a local automatic with no definition, use undefined.
-      else if (TREE_CODE (sym) != RESULT_DECL)
-       return value_range ();
-   }
-  // Otherwise return range for the type.
-  return value_range (type);
-}
-
-
 // This class overloads the ranger routines to provide tracing facilties
 // Entry and exit values to each of the APIs is placed in the dumpfile.
 
@@ -296,4 +252,18 @@ private:
 // Flag to enable debugging the various internal Caches.
 #define DEBUG_RANGE_CACHE (dump_file && (param_evrp_mode & EVRP_MODE_DEBUG))
 
+// Global ranges for SSA names using SSA_NAME_RANGE_INFO.
+
+class global_range_query : public range_query
+{
+public:
+  bool range_of_expr (irange &r, tree expr, gimple * = NULL) OVERRIDE;
+};
+
+extern global_range_query global_ranges;
+extern value_range gimple_range_global (tree name);
+
+extern gimple_ranger *enable_ranger (struct function *);
+extern void disable_ranger (struct function *);
+
 #endif // GCC_GIMPLE_RANGE_STMT_H
index 5f566ae0958fa3fd07c44b6665eb0b70bda9dd24..829fdcdaef2a927e5c2e683610329787f2942ae0 100644 (file)
@@ -60,7 +60,7 @@ public:
     if (dump_file)
       {
        fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
-       m_range_analyzer.dump_all_value_ranges (dump_file);
+       m_range_analyzer.dump (dump_file);
        fprintf (dump_file, "\n");
       }
   }
index 12e6e6f3e22fa0baca2aef25336ba6a9ac559299..b0f1c47f05c8255efd8c150588d886fbfec18aa1 100644 (file)
@@ -4044,7 +4044,7 @@ vrp_prop::finalize ()
   if (dump_file)
     {
       fprintf (dump_file, "\nValue ranges after VRP:\n\n");
-      m_vr_values->dump_all_value_ranges (dump_file);
+      m_vr_values->dump (dump_file);
       fprintf (dump_file, "\n");
     }
 
index 4bb0897c446a025a9a6333c5c3caab7ebf589eac..509d2d33cc528fdc4e54c6cef0ac90b8d012b36b 100644 (file)
@@ -135,6 +135,11 @@ range_query::value_of_stmt (gimple *stmt, tree name)
 
 }
 
+void
+range_query::dump (FILE *)
+{
+}
+
 // valuation_query support routines for value_range_equiv's.
 
 class equiv_allocator : public object_allocator<value_range_equiv>
index e2cbc6852b0c6fed8e50a9738f22170debaa8741..5eff9317ed539548d8025b83531afd1f22e08bc1 100644 (file)
@@ -95,6 +95,7 @@ public:
   // rewrite all uses of it to the above API.
   virtual const class value_range_equiv *get_value_range (const_tree,
                                                          gimple * = NULL);
+  virtual void dump (FILE *);
 
 protected:
   class value_range_equiv *allocate_value_range_equiv ();
index 02bc0db9088deb63eee030b1cdfbb3a019adadab..e0c8844bb0d91cf26b8923e7e812db3efd35c02f 100644 (file)
@@ -1819,7 +1819,7 @@ vr_values::adjust_range_with_scev (value_range_equiv *vr, class loop *loop,
 /* Dump value ranges of all SSA_NAMEs to FILE.  */
 
 void
-vr_values::dump_all_value_ranges (FILE *file)
+vr_values::dump (FILE *file)
 {
   size_t i;
 
index 8c1b2e0a292054d8cc0448e5687d6fd39950df9f..81b9131f7f1cb64a8d2aa16107d173c1fea2ddb5 100644 (file)
@@ -116,7 +116,7 @@ class vr_values : public range_query
   tree op_with_constant_singleton_value_range (tree);
   void adjust_range_with_scev (value_range_equiv *, class loop *,
                               gimple *, tree);
-  void dump_all_value_ranges (FILE *);
+  virtual void dump (FILE *) OVERRIDE;
 
   void extract_range_for_var_from_comparison_expr (tree, enum tree_code,
                                                   tree, tree,