public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 1/5] Common API for accessing global and on-demand ranges.
@ 2021-05-21 11:39 Aldy Hernandez
  2021-05-21 11:39 ` [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun) Aldy Hernandez
                   ` (5 more replies)
  0 siblings, 6 replies; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-21 11:39 UTC (permalink / raw)
  To: GCC patches, Andrew MacLeod; +Cc: Jeff Law, Martin Sebor, Aldy Hernandez

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:

  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:

  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 RANGE_QUERY is tied to cfun, 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 cfun, you can use
GLOBAL_RANGE_QUERY instead of RANGE_QUERY(cfun).  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 ? RANGE_QUERY (cfun) : GLOBAL_RANGE_QUERY;

  query->range_of_expr (range, expr, [stmt]);

By default RANGE_QUERY uses 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_RANGE_QUERY.

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.

Tested on x86-64 Linux.

OK?

gcc/ChangeLog:

	* function.c (allocate_struct_function): Set cfun->x_range_query.
	* function.h (struct function): Declare x_range_query.
	(RANGE_QUERY): New.
	(get_global_range_query): New.
	(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            |   4 ++
 gcc/function.h            |  16 +++++
 gcc/gimple-range-cache.cc |   1 -
 gcc/gimple-range.cc       | 130 ++++++++++++++++++++++++++++++++++++++
 gcc/gimple-range.h        |  60 +++++-------------
 gcc/gimple-ssa-evrp.c     |   2 +-
 gcc/tree-vrp.c            |   2 +-
 gcc/value-query.cc        |   5 ++
 gcc/value-query.h         |   1 +
 gcc/vr-values.c           |   2 +-
 gcc/vr-values.h           |   2 +-
 11 files changed, 175 insertions(+), 50 deletions(-)

diff --git a/gcc/function.c b/gcc/function.c
index fc7b147b5f1..67576950983 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -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
diff --git a/gcc/function.h b/gcc/function.h
index 66cfa973808..41b446bfe7c 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -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,14 @@ extern const char *current_function_name (void);
 
 extern void used_types_insert (tree);
 
+extern range_query *get_global_range_query ();
+
+// Returns the currently active range access class.  This is meant to be used
+// with the `class range_query' API.  When there is no active range class,
+// global ranges are used.
+#define RANGE_QUERY(fun) (fun)->x_range_query
+
+// As above, but for accessing global ranges between passes.
+#define GLOBAL_RANGE_QUERY get_global_range_query ()
+
 #endif  /* GCC_FUNCTION_H */
diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 2c922e32913..c645d15f5af 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -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;
 }
 
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 710bc7f9632..4e1aeee8ed0 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -1402,3 +1402,133 @@ 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;
+
+range_query *
+get_global_range_query ()
+{
+  if (cfun)
+    return RANGE_QUERY (cfun);
+
+  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;
+}
+
+void
+enable_ranger ()
+{
+  gimple_ranger *r;
+
+  if (param_evrp_mode & EVRP_MODE_TRACE)
+    r = new trace_ranger;
+  else
+    r = new gimple_ranger;
+
+  RANGE_QUERY (cfun) = r;
+}
+
+void
+disable_ranger (bool export_ranges)
+{
+  gimple_ranger *r = (gimple_ranger *) RANGE_QUERY (cfun);
+
+  if (export_ranges)
+    r->export_global_ranges ();
+
+  delete r;
+
+  RANGE_QUERY (cfun) = &global_ranges;
+}
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index f33156181bf..1ba073820a6 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -53,7 +53,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;
 protected:
   bool calc_stmt (irange &r, gimple *s, tree name = NULL_TREE);
   bool range_of_range_op (irange &r, gimple *s);
@@ -130,50 +130,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.
 
@@ -202,4 +158,18 @@ private:
 // Temporary external interface to share with vr_values.
 bool range_of_builtin_call (range_query &query, irange &r, gcall *call);
 
+// 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 void enable_ranger ();
+extern void disable_ranger (bool export_ranges = true);
+
 #endif // GCC_GIMPLE_RANGE_STMT_H
diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c
index 5f566ae0958..829fdcdaef2 100644
--- a/gcc/gimple-ssa-evrp.c
+++ b/gcc/gimple-ssa-evrp.c
@@ -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");
       }
   }
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 12e6e6f3e22..b0f1c47f05c 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -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");
     }
 
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 4bb0897c446..509d2d33cc5 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -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>
diff --git a/gcc/value-query.h b/gcc/value-query.h
index e2cbc6852b0..5eff9317ed5 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -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 ();
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index b1bf53af9e0..a89f0b646ae 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -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;
 
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index 8c1b2e0a292..81b9131f7f1 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -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,
-- 
2.31.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun).
  2021-05-21 11:39 [PATCH 1/5] Common API for accessing global and on-demand ranges Aldy Hernandez
@ 2021-05-21 11:39 ` Aldy Hernandez
  2021-05-25  8:43   ` Richard Biener
  2021-05-25 16:17   ` Aldy Hernandez
  2021-05-21 11:39 ` [PATCH 3/5] Convert evrp " Aldy Hernandez
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-21 11:39 UTC (permalink / raw)
  To: GCC patches, Andrew MacLeod; +Cc: Jeff Law, Martin Sebor, Aldy Hernandez

This patch converts the Walloca pass to use an on-demand ranger
accesible with RANGE_QUERY instead of having to create a ranger and pass
it around.

Tested on x86-64 Linux.

OK?

gcc/ChangeLog:

	* gimple-ssa-warn-alloca.c (alloca_call_type): Use RANGE_QUERY
	instead of query argument.
	(pass_walloca::execute): Enable and disable global ranger.
---
 gcc/gimple-ssa-warn-alloca.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
index e9a24d4d1d0..12f4bce3be8 100644
--- a/gcc/gimple-ssa-warn-alloca.c
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -165,7 +165,7 @@ adjusted_warn_limit (bool idx)
 // call was created by the gimplifier for a VLA.
 
 static class alloca_type_and_limit
-alloca_call_type (range_query &query, gimple *stmt, bool is_vla)
+alloca_call_type (gimple *stmt, bool is_vla)
 {
   gcc_assert (gimple_alloca_call_p (stmt));
   tree len = gimple_call_arg (stmt, 0);
@@ -217,7 +217,7 @@ alloca_call_type (range_query &query, gimple *stmt, bool is_vla)
   int_range_max r;
   if (warn_limit_specified_p (is_vla)
       && TREE_CODE (len) == SSA_NAME
-      && query.range_of_expr (r, len, stmt)
+      && RANGE_QUERY (cfun)->range_of_expr (r, len, stmt)
       && !r.varying_p ())
     {
       // The invalid bits are anything outside of [0, MAX_SIZE].
@@ -256,7 +256,7 @@ in_loop_p (gimple *stmt)
 unsigned int
 pass_walloca::execute (function *fun)
 {
-  gimple_ranger ranger;
+  enable_ranger ();
   basic_block bb;
   FOR_EACH_BB_FN (bb, fun)
     {
@@ -290,7 +290,7 @@ pass_walloca::execute (function *fun)
 	    continue;
 
 	  class alloca_type_and_limit t
-	    = alloca_call_type (ranger, stmt, is_vla);
+	    = alloca_call_type (stmt, is_vla);
 
 	  unsigned HOST_WIDE_INT adjusted_alloca_limit
 	    = adjusted_warn_limit (false);
@@ -383,6 +383,7 @@ pass_walloca::execute (function *fun)
 	    }
 	}
     }
+  disable_ranger ();
   return 0;
 }
 
-- 
2.31.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 3/5] Convert evrp pass to RANGE_QUERY(cfun).
  2021-05-21 11:39 [PATCH 1/5] Common API for accessing global and on-demand ranges Aldy Hernandez
  2021-05-21 11:39 ` [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun) Aldy Hernandez
@ 2021-05-21 11:39 ` Aldy Hernandez
  2021-05-25 16:18   ` Aldy Hernandez
  2021-05-21 11:39 ` [PATCH 4/5] Convert remaining passes to RANGE_QUERY Aldy Hernandez
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-21 11:39 UTC (permalink / raw)
  To: GCC patches, Andrew MacLeod; +Cc: Jeff Law, Martin Sebor, Aldy Hernandez

Some tests required tweaking, as exporting global ranges from evrp will
now provide better ranges for subsequent passes.

Tested on x86-64 Linux.

OK?

gcc/ChangeLog:

	* gimple-ssa-evrp.c (rvrp_folder): Call enable_ranger.  Use
	RANGE_QUERY.
	(~rvrp_folder): Call disable_ranger.
	(hybrid_folder::value_of_expr): Use global ranger.
	(hybrid_folder::value_on_edge): Same.
	(hybrid_folder::value_of_stmt): Same.

gcc/testsuite/ChangeLog:

	* gcc.dg/Wstringop-overflow-55.c: Remove xfail.
	* gcc.dg/pr80776-1.c: Same.
---
 gcc/gimple-ssa-evrp.c                        | 43 +++++++++-----------
 gcc/testsuite/gcc.dg/Wstringop-overflow-55.c |  8 ++--
 gcc/testsuite/gcc.dg/pr80776-1.c             |  4 +-
 3 files changed, 24 insertions(+), 31 deletions(-)

diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c
index 829fdcdaef2..bd4c7634b3e 100644
--- a/gcc/gimple-ssa-evrp.c
+++ b/gcc/gimple-ssa-evrp.c
@@ -117,34 +117,33 @@ class rvrp_folder : public substitute_and_fold_engine
 public:
 
   rvrp_folder () : substitute_and_fold_engine (), m_simplifier ()
-  { 
-    if (param_evrp_mode & EVRP_MODE_TRACE)
-      m_ranger = new trace_ranger ();
-    else
-      m_ranger = new gimple_ranger ();
-    m_simplifier.set_range_query (m_ranger);
+  {
+    enable_ranger ();
+
+    m_simplifier.set_range_query (RANGE_QUERY (cfun));
   }
       
   ~rvrp_folder ()
   {
     if (dump_file && (dump_flags & TDF_DETAILS))
-      m_ranger->dump (dump_file);
-    delete m_ranger;
+      RANGE_QUERY (cfun)->dump (dump_file);
+
+    disable_ranger ();
   }
 
   tree value_of_expr (tree name, gimple *s = NULL) OVERRIDE
   {
-    return m_ranger->value_of_expr (name, s);
+    return RANGE_QUERY (cfun)->value_of_expr (name, s);
   }
 
   tree value_on_edge (edge e, tree name) OVERRIDE
   {
-    return m_ranger->value_on_edge (e, name);
+    return RANGE_QUERY (cfun)->value_on_edge (e, name);
   }
 
   tree value_of_stmt (gimple *s, tree name = NULL) OVERRIDE
   {
-    return m_ranger->value_of_stmt (s, name);
+    return RANGE_QUERY (cfun)->value_of_stmt (s, name);
   }
 
   bool fold_stmt (gimple_stmt_iterator *gsi) OVERRIDE
@@ -154,7 +153,6 @@ public:
 
 private:
   DISABLE_COPY_AND_ASSIGN (rvrp_folder);
-  gimple_ranger *m_ranger;
   simplify_using_ranges m_simplifier;
 };
 
@@ -175,19 +173,16 @@ class hybrid_folder : public evrp_folder
 public:
   hybrid_folder (bool evrp_first)
   {
-    if (param_evrp_mode & EVRP_MODE_TRACE)
-      m_ranger = new trace_ranger ();
-    else
-      m_ranger = new gimple_ranger ();
+    enable_ranger ();
 
     if (evrp_first)
       {
 	first = &m_range_analyzer;
-	second = m_ranger;
+	second = RANGE_QUERY (cfun);
       }
      else
       {
-	first = m_ranger;
+	first = RANGE_QUERY (cfun);
 	second = &m_range_analyzer;
       }
   }
@@ -195,8 +190,9 @@ public:
   ~hybrid_folder ()
   {
     if (dump_file && (dump_flags & TDF_DETAILS))
-      m_ranger->dump (dump_file);
-    delete m_ranger;
+      RANGE_QUERY (cfun)->dump (dump_file);
+
+    disable_ranger ();
   }
 
   bool fold_stmt (gimple_stmt_iterator *gsi) OVERRIDE
@@ -221,7 +217,6 @@ public:
 
 private:
   DISABLE_COPY_AND_ASSIGN (hybrid_folder);
-  gimple_ranger *m_ranger;
   range_query *first;
   range_query *second;
   tree choose_value (tree evrp_val, tree ranger_val);
@@ -232,7 +227,7 @@ tree
 hybrid_folder::value_of_expr (tree op, gimple *stmt)
 {
   tree evrp_ret = evrp_folder::value_of_expr (op, stmt);
-  tree ranger_ret = m_ranger->value_of_expr (op, stmt);
+  tree ranger_ret = RANGE_QUERY (cfun)->value_of_expr (op, stmt);
   return choose_value (evrp_ret, ranger_ret);
 }
 
@@ -242,7 +237,7 @@ hybrid_folder::value_on_edge (edge e, tree op)
   // Call evrp::value_of_expr directly.  Otherwise another dual call is made
   // via hybrid_folder::value_of_expr, but without an edge.
   tree evrp_ret = evrp_folder::value_of_expr (op, NULL);
-  tree ranger_ret = m_ranger->value_on_edge (e, op);
+  tree ranger_ret = RANGE_QUERY (cfun)->value_on_edge (e, op);
   return choose_value (evrp_ret, ranger_ret);
 }
 
@@ -257,7 +252,7 @@ hybrid_folder::value_of_stmt (gimple *stmt, tree op)
   else
     evrp_ret = NULL_TREE;
 
-  tree ranger_ret = m_ranger->value_of_stmt (stmt, op);
+  tree ranger_ret = RANGE_QUERY (cfun)->value_of_stmt (stmt, op);
   return choose_value (evrp_ret, ranger_ret);
 }
 
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c
index 25f5b82d9be..8df5cb629ae 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c
@@ -66,7 +66,7 @@ void warn_ptrdiff_anti_range_add (ptrdiff_t i)
 {
   i |= 1;
 
-  char ca5[5];              // { dg-message "at offset \\\[1, 5]" "pr?????" { xfail *-*-* } }
+  char ca5[5];              // { dg-message "at offset \\\[1, 5]" "pr?????" }
   char *p0 = ca5;           // offset
   char *p1 = p0 + i;        //  1-5
   char *p2 = p1 + i;        //  2-5
@@ -74,7 +74,7 @@ void warn_ptrdiff_anti_range_add (ptrdiff_t i)
   char *p4 = p3 + i;        //  4-5
   char *p5 = p4 + i;        //   5
 
-  memset (p5, 0, 5);        // { dg-warning "writing 5 bytes into a region of size 0" "pr?????" { xfail *-*-* } }
+  memset (p5, 0, 5);        // { dg-warning "writing 5 bytes into a region of size" "pr?????" }
 
   sink (p0, p1, p2, p3, p4, p5);
 }
@@ -83,7 +83,7 @@ void warn_int_anti_range (int i)
 {
   i |= 1;
 
-  char ca5[5];              // { dg-message "at offset \\\[1, 5]" "pr?????" { xfail *-*-* } }
+  char ca5[5];              // { dg-message "at offset \\\[1, 5]" "pr?????" }
   char *p0 = ca5;           // offset
   char *p1 = p0 + i;        //  1-5
   char *p2 = p1 + i;        //  2-5
@@ -91,7 +91,7 @@ void warn_int_anti_range (int i)
   char *p4 = p3 + i;        //  4-5
   char *p5 = p4 + i;        //   5
 
-  memset (p5, 0, 5);        // { dg-warning "writing 5 bytes into a region of size 0" "pr?????" { xfail *-*-* } }
+  memset (p5, 0, 5);        // { dg-warning "writing 5 bytes into a region of size" "pr?????" }
 
   sink (p0, p1, p2, p3, p4, p5);
 }
diff --git a/gcc/testsuite/gcc.dg/pr80776-1.c b/gcc/testsuite/gcc.dg/pr80776-1.c
index af41c0c2ffa..f3a120b6744 100644
--- a/gcc/testsuite/gcc.dg/pr80776-1.c
+++ b/gcc/testsuite/gcc.dg/pr80776-1.c
@@ -17,7 +17,5 @@ Foo (void)
     __builtin_unreachable ();
   if (! (0 <= i && i <= 999999))
     __builtin_unreachable ();
-  /* The correctness bits for [E]VRP cannot handle chained conditionals
-     when deciding to ignore a unreachable branch for setting SSA range info. */
-  sprintf (number, "%d", i); /* { dg-bogus "writing" "" { xfail *-*-* } } */
+  sprintf (number, "%d", i); /* { dg-bogus "writing" "" } */
 }
-- 
2.31.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 4/5] Convert remaining passes to RANGE_QUERY.
  2021-05-21 11:39 [PATCH 1/5] Common API for accessing global and on-demand ranges Aldy Hernandez
  2021-05-21 11:39 ` [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun) Aldy Hernandez
  2021-05-21 11:39 ` [PATCH 3/5] Convert evrp " Aldy Hernandez
@ 2021-05-21 11:39 ` Aldy Hernandez
  2021-05-24 19:34   ` Martin Sebor
  2021-05-25 16:19   ` Aldy Hernandez
  2021-05-21 11:39 ` [PATCH 5/5] Cleanup get_range_info Aldy Hernandez
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-21 11:39 UTC (permalink / raw)
  To: GCC patches, Andrew MacLeod; +Cc: Jeff Law, Martin Sebor, Aldy Hernandez

This patch converts the remaining users of get_range_info and
get_ptr_nonnull to the range_query API.

No effort was made to move passes away from VR_ANTI_RANGE, or any other
use of deprecated methods.  This was a straight up conversion to the new
API, nothing else.

Tested on x86-64 Linux.

OK?

gcc/ChangeLog:

	* builtins.c (check_nul_terminated_array): Convert to RANGE_QUERY.
	(expand_builtin_strnlen): Same.
	(determine_block_size): Same.
	* fold-const.c (expr_not_equal_to): Same.
	* gimple-fold.c (size_must_be_zero_p): Same.
	* gimple-match-head.c: Include gimple-range.h.
	* gimple-pretty-print.c (dump_ssaname_info): Convert to RANGE_QUERY.
	* gimple-ssa-warn-restrict.c
	(builtin_memref::extend_offset_range): Same.
	* graphite-sese-to-poly.c (add_param_constraints): Same.
	* internal-fn.c (get_min_precision): Same.
	* ipa-fnsummary.c (set_switch_stmt_execution_predicate): Same.
	* ipa-prop.c (ipa_compute_jump_functions_for_edge): Same.
	* match.pd: Same.
	* tree-data-ref.c (split_constant_offset): Same.
	(dr_step_indicator): Same.
	* tree-dfa.c (get_ref_base_and_extent): Same.
	* tree-scalar-evolution.c (iv_can_overflow_p): Same.
	* tree-ssa-loop-niter.c (refine_value_range_using_guard): Same.
	(determine_value_range): Same.
	(record_nonwrapping_iv): Same.
	(infer_loop_bounds_from_signedness): Same.
	(scev_var_range_cant_overflow): Same.
	* tree-ssa-phiopt.c (two_value_replacement): Same.
	* tree-ssa-pre.c (insert_into_preds_of_block): Same.
	* tree-ssa-reassoc.c (optimize_range_tests_to_bit_test): Same.
	* tree-ssa-strlen.c (handle_builtin_stxncpy_strncat): Same.
	(get_range): Same.
	(dump_strlen_info): Same.
	(set_strlen_range): Same.
	(maybe_diag_stxncpy_trunc): Same.
	(get_len_or_size): Same.
	(handle_integral_assign): Same.
	* tree-ssa-structalias.c (find_what_p_points_to): Same.
	* tree-ssa-uninit.c (find_var_cmp_const): Same.
	* tree-switch-conversion.c (bit_test_cluster::emit): Same.
	* tree-vect-patterns.c (vect_get_range_info): Same.
	(vect_recog_divmod_pattern): Same.
	* tree-vrp.c (intersect_range_with_nonzero_bits): Same.
	(register_edge_assert_for_2): Same.
	(determine_value_range_1): Same.
	* tree.c (get_range_pos_neg): Same.
	* vr-values.c (vr_values::get_lattice_entry): Same.
	(vr_values::update_value_range): Same.
	(simplify_conversion_using_ranges): Same.
---
 gcc/builtins.c                 | 40 ++++++++++------
 gcc/fold-const.c               |  8 +++-
 gcc/gimple-fold.c              |  7 ++-
 gcc/gimple-match-head.c        |  1 +
 gcc/gimple-pretty-print.c      | 12 ++++-
 gcc/gimple-ssa-warn-restrict.c |  8 +++-
 gcc/graphite-sese-to-poly.c    |  9 +++-
 gcc/internal-fn.c              | 14 +++---
 gcc/ipa-fnsummary.c            | 11 ++++-
 gcc/ipa-prop.c                 | 16 +++----
 gcc/match.pd                   | 19 ++++++--
 gcc/tree-data-ref.c            | 24 ++++++++--
 gcc/tree-dfa.c                 | 14 +++++-
 gcc/tree-scalar-evolution.c    | 13 +++++-
 gcc/tree-ssa-loop-niter.c      | 81 +++++++++++++++++++++-----------
 gcc/tree-ssa-phiopt.c          | 11 ++++-
 gcc/tree-ssa-pre.c             | 19 ++++----
 gcc/tree-ssa-reassoc.c         |  9 ++--
 gcc/tree-ssa-strlen.c          | 85 ++++++++++++++++++++--------------
 gcc/tree-ssa-structalias.c     |  8 ++--
 gcc/tree-ssa-uninit.c          |  8 +++-
 gcc/tree-switch-conversion.c   | 10 ++--
 gcc/tree-vect-patterns.c       | 18 +++++--
 gcc/tree-vrp.c                 | 21 ++++-----
 gcc/tree.c                     | 13 +++---
 gcc/vr-values.c                | 12 +++--
 26 files changed, 332 insertions(+), 159 deletions(-)

diff --git a/gcc/builtins.c b/gcc/builtins.c
index e1b284846b1..deb7c083315 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-outof-ssa.h"
 #include "attr-fnspec.h"
 #include "demangle.h"
+#include "gimple-range.h"
 
 struct target_builtins default_target_builtins;
 #if SWITCHABLE_TARGET
@@ -1214,14 +1215,15 @@ check_nul_terminated_array (tree expr, tree src,
   wide_int bndrng[2];
   if (bound)
     {
-      if (TREE_CODE (bound) == INTEGER_CST)
-	bndrng[0] = bndrng[1] = wi::to_wide (bound);
-      else
-	{
-	  value_range_kind rng = get_range_info (bound, bndrng, bndrng + 1);
-	  if (rng != VR_RANGE)
-	    return true;
-	}
+      value_range r;
+
+      GLOBAL_RANGE_QUERY->range_of_expr (r, bound);
+
+      if (r.kind () != VR_RANGE)
+	return true;
+
+      bndrng[0] = r.lower_bound ();
+      bndrng[1] = r.upper_bound ();
 
       if (exact)
 	{
@@ -3827,9 +3829,12 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
     return NULL_RTX;
 
   wide_int min, max;
-  enum value_range_kind rng = get_range_info (bound, &min, &max);
-  if (rng != VR_RANGE)
+  value_range r;
+  GLOBAL_RANGE_QUERY->range_of_expr (r, bound);
+  if (r.kind () != VR_RANGE)
     return NULL_RTX;
+  min = r.lower_bound ();
+  max = r.upper_bound ();
 
   if (!len || TREE_CODE (len) != INTEGER_CST)
     {
@@ -3897,7 +3902,16 @@ determine_block_size (tree len, rtx len_rtx,
 	*probable_max_size = *max_size = GET_MODE_MASK (GET_MODE (len_rtx));
 
       if (TREE_CODE (len) == SSA_NAME)
-	range_type = get_range_info (len, &min, &max);
+	{
+	  value_range r;
+	  GLOBAL_RANGE_QUERY->range_of_expr (r, len);
+	  range_type = r.kind ();
+	  if (range_type != VR_UNDEFINED)
+	    {
+	      min = wi::to_wide (r.min ());
+	      max = wi::to_wide (r.max ());
+	    }
+	}
       if (range_type == VR_RANGE)
 	{
 	  if (wi::fits_uhwi_p (min) && *min_size < min.to_uhwi ())
@@ -4914,8 +4928,8 @@ check_read_access (tree exp, tree src, tree bound /* = NULL_TREE */,
 /* If STMT is a call to an allocation function, returns the constant
    maximum size of the object allocated by the call represented as
    sizetype.  If nonnull, sets RNG1[] to the range of the size.
-   When nonnull, uses RVALS for range information, otherwise calls
-   get_range_info to get it.
+   When nonnull, uses RVALS for range information, otherwise gets global
+   range info.
    Returns null when STMT is not a call to a valid allocation function.  */
 
 tree
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 5a41524702b..d680ba1442f 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -83,6 +83,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vector-builder.h"
 #include "vec-perm-indices.h"
 #include "asan.h"
+#include "gimple-range.h"
 
 /* Nonzero if we are folding constants inside an initializer; zero
    otherwise.  */
@@ -10686,7 +10687,12 @@ expr_not_equal_to (tree t, const wide_int &w)
     case SSA_NAME:
       if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
 	return false;
-      get_range_info (t, vr);
+
+      if (cfun)
+	RANGE_QUERY (cfun)->range_of_expr (vr, t);
+      else
+	GLOBAL_RANGE_QUERY->range_of_expr (vr, t);
+
       if (!vr.undefined_p ()
 	  && !vr.contains_p (wide_int_to_tree (TREE_TYPE (t), w)))
 	return true;
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 68717cf1542..228fa1b357f 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -873,7 +873,12 @@ size_must_be_zero_p (tree size)
   value_range valid_range (build_int_cst (type, 0),
 			   wide_int_to_tree (type, ssize_max));
   value_range vr;
-  get_range_info (size, vr);
+  if (cfun)
+    RANGE_QUERY (cfun)->range_of_expr (vr, size);
+  else
+    GLOBAL_RANGE_QUERY->range_of_expr (vr, size);
+  if (vr.undefined_p ())
+    vr.set_varying (TREE_TYPE (size));
   vr.intersect (&valid_range);
   return vr.zero_p ();
 }
diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c
index b084a31572a..7112c116835 100644
--- a/gcc/gimple-match-head.c
+++ b/gcc/gimple-match-head.c
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-eh.h"
 #include "dbgcnt.h"
 #include "tm.h"
+#include "gimple-range.h"
 
 /* Forward declarations of the private auto-generated matchers.
    They expect valueized operands in canonical order and do not
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 0ef01e6420b..62d895d1625 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "asan.h"
 #include "cfgloop.h"
+#include "gimple-range.h"
 
 /* Disable warnings about quoting issues in the pp_xxx calls below
    that (intentionally) don't follow GCC diagnostic conventions.  */
@@ -2263,8 +2264,17 @@ dump_ssaname_info (pretty_printer *buffer, tree node, int spc)
       && SSA_NAME_RANGE_INFO (node))
     {
       wide_int min, max, nonzero_bits;
-      value_range_kind range_type = get_range_info (node, &min, &max);
+      value_range r;
 
+      GLOBAL_RANGE_QUERY->range_of_expr (r, node);
+      value_range_kind range_type = r.kind ();
+      if (!r.undefined_p ())
+	{
+	  min = wi::to_wide (r.min ());
+	  max = wi::to_wide (r.max ());
+	}
+
+      // FIXME: Use irange::dump() instead.
       if (range_type == VR_VARYING)
 	pp_printf (buffer, "# RANGE VR_VARYING");
       else if (range_type == VR_RANGE || range_type == VR_ANTI_RANGE)
diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
index ad37f20afaa..a59731c2bc2 100644
--- a/gcc/gimple-ssa-warn-restrict.c
+++ b/gcc/gimple-ssa-warn-restrict.c
@@ -349,7 +349,13 @@ builtin_memref::extend_offset_range (tree offset)
 	  /* There is a global version here because
 	     check_bounds_or_overlap may be called from gimple
 	     fold during gimple lowering.  */
-	  rng = get_range_info (offset, &min, &max);
+	  RANGE_QUERY (cfun)->range_of_expr (vr, offset, stmt);
+	  rng = vr.kind ();
+	  if (!vr.undefined_p ())
+	    {
+	      min = wi::to_wide (vr.min ());
+	      max = wi::to_wide (vr.max ());
+	    }
 	}
       if (rng == VR_ANTI_RANGE && wi::lts_p (max, min))
 	{
diff --git a/gcc/graphite-sese-to-poly.c b/gcc/graphite-sese-to-poly.c
index eebf2e02cfc..2d332f69a92 100644
--- a/gcc/graphite-sese-to-poly.c
+++ b/gcc/graphite-sese-to-poly.c
@@ -418,13 +418,18 @@ static void
 add_param_constraints (scop_p scop, graphite_dim_t p, tree parameter)
 {
   tree type = TREE_TYPE (parameter);
+  value_range r;
   wide_int min, max;
 
   gcc_assert (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type));
 
   if (INTEGRAL_TYPE_P (type)
-      && get_range_info (parameter, &min, &max) == VR_RANGE)
-    ;
+      && RANGE_QUERY (cfun)->range_of_expr (r, parameter)
+      && !r.undefined_p ())
+    {
+      min = r.lower_bound ();
+      max = r.upper_bound ();
+    }
   else
     {
       min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index d209a52f823..dd1f204863e 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ssa-iterators.h"
 #include "explow.h"
 #include "rtl-iter.h"
+#include "gimple-range.h"
 
 /* The names of each internal function, indexed by function number.  */
 const char *const internal_fn_name_array[] = {
@@ -680,8 +681,9 @@ get_min_precision (tree arg, signop sign)
     }
   if (TREE_CODE (arg) != SSA_NAME)
     return prec + (orig_sign != sign);
-  wide_int arg_min, arg_max;
-  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
+  value_range r;
+  while (!GLOBAL_RANGE_QUERY->range_of_expr (r, arg)
+	 || r.kind () != VR_RANGE)
     {
       gimple *g = SSA_NAME_DEF_STMT (arg);
       if (is_gimple_assign (g)
@@ -709,14 +711,14 @@ get_min_precision (tree arg, signop sign)
     }
   if (sign == TYPE_SIGN (TREE_TYPE (arg)))
     {
-      int p1 = wi::min_precision (arg_min, sign);
-      int p2 = wi::min_precision (arg_max, sign);
+      int p1 = wi::min_precision (r.lower_bound (), sign);
+      int p2 = wi::min_precision (r.upper_bound (), sign);
       p1 = MAX (p1, p2);
       prec = MIN (prec, p1);
     }
-  else if (sign == UNSIGNED && !wi::neg_p (arg_min, SIGNED))
+  else if (sign == UNSIGNED && !wi::neg_p (r.lower_bound (), SIGNED))
     {
-      int p = wi::min_precision (arg_max, UNSIGNED);
+      int p = wi::min_precision (r.upper_bound (), UNSIGNED);
       prec = MIN (prec, p);
     }
   return prec + (orig_sign != sign);
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 4e5be812734..299d7fc1f60 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -85,6 +85,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "tree-into-ssa.h"
 #include "symtab-clones.h"
+#include "gimple-range.h"
 
 /* Summaries.  */
 fast_function_summary <ipa_fn_summary *, va_gc> *ipa_fn_summaries;
@@ -1687,8 +1688,14 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
   int bound_limit = opt_for_fn (fbi->node->decl,
 				param_ipa_max_switch_predicate_bounds);
   int bound_count = 0;
-  wide_int vr_wmin, vr_wmax;
-  value_range_kind vr_type = get_range_info (op, &vr_wmin, &vr_wmax);
+  value_range vr;
+
+  RANGE_QUERY (cfun)->range_of_expr (vr, op);
+  if (vr.undefined_p ())
+    vr.set_varying (TREE_TYPE (op));
+  value_range_kind vr_type = vr.kind ();
+  wide_int vr_wmin = wi::to_wide (vr.min ());
+  wide_int vr_wmax = wi::to_wide (vr.max ());
 
   FOR_EACH_EDGE (e, ei, bb->succs)
     {
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 0591ef1b569..02f422bdbf3 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -55,6 +55,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "options.h"
 #include "symtab-clones.h"
 #include "attr-fnspec.h"
+#include "gimple-range.h"
 
 /* Function summary where the parameter infos are actually stored. */
 ipa_node_params_t *ipa_node_params_sum = NULL;
@@ -2237,6 +2238,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
   gcall *call = cs->call_stmt;
   int n, arg_num = gimple_call_num_args (call);
   bool useful_context = false;
+  value_range vr;
 
   if (arg_num == 0 || args->jump_functions)
     return;
@@ -2274,7 +2276,8 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 
 	  if (TREE_CODE (arg) == SSA_NAME
 	      && param_type
-	      && get_ptr_nonnull (arg))
+	      && RANGE_QUERY (cfun)->range_of_expr (vr, arg)
+	      && vr.nonzero_p ())
 	    addr_nonzero = true;
 	  else if (tree_single_nonzero_warnv_p (arg, &strict_overflow))
 	    addr_nonzero = true;
@@ -2289,19 +2292,14 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	}
       else
 	{
-	  wide_int min, max;
-	  value_range_kind kind;
 	  if (TREE_CODE (arg) == SSA_NAME
 	      && param_type
-	      && (kind = get_range_info (arg, &min, &max))
-	      && (kind == VR_RANGE || kind == VR_ANTI_RANGE))
+	      && RANGE_QUERY (cfun)->range_of_expr (vr, arg)
+	      && !vr.undefined_p ())
 	    {
 	      value_range resvr;
-	      value_range tmpvr (wide_int_to_tree (TREE_TYPE (arg), min),
-				 wide_int_to_tree (TREE_TYPE (arg), max),
-				 kind);
 	      range_fold_unary_expr (&resvr, NOP_EXPR, param_type,
-				     &tmpvr, TREE_TYPE (arg));
+				     &vr, TREE_TYPE (arg));
 	      if (!resvr.undefined_p () && !resvr.varying_p ())
 		ipa_set_jfunc_vr (jfunc, &resvr);
 	      else
diff --git a/gcc/match.pd b/gcc/match.pd
index cdb87636951..9dddf5ebd0a 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -663,11 +663,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (with
      {
        bool overflowed = true;
-       wide_int wmin0, wmax0, wmin1, wmax1;
+       value_range vr0, vr1;
        if (INTEGRAL_TYPE_P (type)
-	   && get_range_info (@0, &wmin0, &wmax0) == VR_RANGE
-	   && get_range_info (@1, &wmin1, &wmax1) == VR_RANGE)
+	   && GLOBAL_RANGE_QUERY->range_of_expr (vr0, @0)
+	   && GLOBAL_RANGE_QUERY->range_of_expr (vr1, @1)
+	   && vr0.kind () == VR_RANGE
+	   && vr1.kind () == VR_RANGE)
 	 {
+	   wide_int wmin0 = vr0.lower_bound ();
+	   wide_int wmax0 = vr0.upper_bound ();
+	   wide_int wmin1 = vr1.lower_bound ();
+	   wide_int wmax1 = vr1.upper_bound ();
 	   /* If the multiplication can't overflow/wrap around, then
 	      it can be optimized too.  */
 	   wi::overflow_type min_ovf, max_ovf;
@@ -2509,9 +2515,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 	  = wide_int::from (wi::to_wide (@1), TYPE_PRECISION (inner_type),
 			    TYPE_SIGN (inner_type));
 
-        wide_int wmin0, wmax0;
-        if (get_range_info (@0, &wmin0, &wmax0) == VR_RANGE)
+	value_range vr;
+	if (GLOBAL_RANGE_QUERY->range_of_expr (vr, @0)
+	    && vr.kind () == VR_RANGE)
           {
+	    wide_int wmin0 = vr.lower_bound ();
+	    wide_int wmax0 = vr.upper_bound ();
             wi::add (wmin0, w1, TYPE_SIGN (inner_type), &min_ovf);
             wi::add (wmax0, w1, TYPE_SIGN (inner_type), &max_ovf);
           }
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index e6dd5f15bed..5ba41e2c73d 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -1035,14 +1035,23 @@ split_constant_offset (tree exp, tree *var, tree *off, value_range *exp_range,
       *exp_range = type;
       if (code == SSA_NAME)
 	{
-	  wide_int var_min, var_max;
-	  value_range_kind vr_kind = get_range_info (exp, &var_min, &var_max);
+	  value_range vr;
+	  RANGE_QUERY (cfun)->range_of_expr (vr, exp);
+	  if (vr.undefined_p ())
+	    vr.set_varying (TREE_TYPE (exp));
+	  wide_int var_min = wi::to_wide (vr.min ());
+	  wide_int var_max = wi::to_wide (vr.max ());
+	  value_range_kind vr_kind = vr.kind ();
 	  wide_int var_nonzero = get_nonzero_bits (exp);
 	  vr_kind = intersect_range_with_nonzero_bits (vr_kind,
 						       &var_min, &var_max,
 						       var_nonzero,
 						       TYPE_SIGN (type));
-	  if (vr_kind == VR_RANGE)
+	  /* This check for VR_VARYING is here because the old code
+	     using get_range_info would return VR_RANGE for the entire
+	     domain, instead of VR_VARYING.  The new code normalizes
+	     full-domain ranges to VR_VARYING.  */
+	  if (vr_kind == VR_RANGE || vr_kind == VR_VARYING)
 	    *exp_range = value_range (type, var_min, var_max);
 	}
     }
@@ -6298,12 +6307,19 @@ dr_step_indicator (struct data_reference *dr, int useful_min)
 
       /* Get the range of values that the unconverted step actually has.  */
       wide_int step_min, step_max;
+      value_range vr;
       if (TREE_CODE (step) != SSA_NAME
-	  || get_range_info (step, &step_min, &step_max) != VR_RANGE)
+	  || !RANGE_QUERY (cfun)->range_of_expr (vr, step)
+	  || vr.kind () != VR_RANGE)
 	{
 	  step_min = wi::to_wide (TYPE_MIN_VALUE (type));
 	  step_max = wi::to_wide (TYPE_MAX_VALUE (type));
 	}
+      else
+	{
+	  step_min = vr.lower_bound ();
+	  step_max = vr.upper_bound ();
+	}
 
       /* Check whether the unconverted step has an acceptable range.  */
       signop sgn = TYPE_SIGN (type);
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 0482b05e26c..e9cf4bfa706 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-iterator.h"
 #include "gimple-walk.h"
 #include "tree-dfa.h"
+#include "gimple-range.h"
 
 /* Build and maintain data flow information for trees.  */
 
@@ -530,14 +531,23 @@ get_ref_base_and_extent (tree exp, poly_int64_pod *poffset,
 		   index.  */
 		seen_variable_array_ref = true;
 
-		wide_int min, max;
+		value_range vr;
+		range_query *query;
+		if (cfun)
+		  query = RANGE_QUERY (cfun);
+		else
+		  query = GLOBAL_RANGE_QUERY;
+
 		if (TREE_CODE (index) == SSA_NAME
 		    && (low_bound = array_ref_low_bound (exp),
 			poly_int_tree_p (low_bound))
 		    && (unit_size = array_ref_element_size (exp),
 			TREE_CODE (unit_size) == INTEGER_CST)
-		    && get_range_info (index, &min, &max) == VR_RANGE)
+		    && query->range_of_expr (vr, index)
+		    && vr.kind () == VR_RANGE)
 		  {
+		    wide_int min = vr.lower_bound ();
+		    wide_int max = vr.upper_bound ();
 		    poly_offset_int lbound = wi::to_poly_offset (low_bound);
 		    /* Try to constrain maxsize with range information.  */
 		    offset_int omax
diff --git a/gcc/tree-scalar-evolution.c b/gcc/tree-scalar-evolution.c
index ff052be1021..f0f28f26042 100644
--- a/gcc/tree-scalar-evolution.c
+++ b/gcc/tree-scalar-evolution.c
@@ -3039,18 +3039,27 @@ iv_can_overflow_p (class loop *loop, tree type, tree base, tree step)
   widest_int nit;
   wide_int base_min, base_max, step_min, step_max, type_min, type_max;
   signop sgn = TYPE_SIGN (type);
+  value_range r;
 
   if (integer_zerop (step))
     return false;
 
   if (!INTEGRAL_TYPE_P (TREE_TYPE (base))
-      || get_range_info (base, &base_min, &base_max) != VR_RANGE)
+      || !RANGE_QUERY (cfun)->range_of_expr (r, base)
+      || r.kind () != VR_RANGE)
     return true;
 
+  base_min = r.lower_bound ();
+  base_max = r.upper_bound ();
+
   if (!INTEGRAL_TYPE_P (TREE_TYPE (step))
-      || get_range_info (step, &step_min, &step_max) != VR_RANGE)
+      || !RANGE_QUERY (cfun)->range_of_expr (r, step)
+      || r.kind () != VR_RANGE)
     return true;
 
+  step_min = r.lower_bound ();
+  step_max = r.upper_bound ();
+
   if (!get_max_loop_iterations (loop, &nit))
     return true;
 
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 3817ec423e7..bfbb11c59c5 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-chrec.h"
 #include "tree-scalar-evolution.h"
 #include "tree-dfa.h"
+#include "gimple-range.h"
 
 
 /* The maximum number of dominator BBs we search for conditions
@@ -121,7 +122,6 @@ refine_value_range_using_guard (tree type, tree var,
   tree varc0, varc1, ctype;
   mpz_t offc0, offc1;
   mpz_t mint, maxt, minc1, maxc1;
-  wide_int minv, maxv;
   bool no_wrap = nowrap_type_p (type);
   bool c0_ok, c1_ok;
   signop sgn = TYPE_SIGN (type);
@@ -221,6 +221,7 @@ refine_value_range_using_guard (tree type, tree var,
   get_type_static_bounds (type, mint, maxt);
   mpz_init (minc1);
   mpz_init (maxc1);
+  value_range r;
   /* Setup range information for varc1.  */
   if (integer_zerop (varc1))
     {
@@ -229,11 +230,12 @@ refine_value_range_using_guard (tree type, tree var,
     }
   else if (TREE_CODE (varc1) == SSA_NAME
 	   && INTEGRAL_TYPE_P (type)
-	   && get_range_info (varc1, &minv, &maxv) == VR_RANGE)
+	   && RANGE_QUERY (cfun)->range_of_expr (r, varc1)
+	   && r.kind () == VR_RANGE)
     {
-      gcc_assert (wi::le_p (minv, maxv, sgn));
-      wi::to_mpz (minv, minc1, sgn);
-      wi::to_mpz (maxv, maxc1, sgn);
+      gcc_assert (wi::le_p (r.lower_bound (), r.upper_bound (), sgn));
+      wi::to_mpz (r.lower_bound (), minc1, sgn);
+      wi::to_mpz (r.upper_bound (), maxc1, sgn);
     }
   else
     {
@@ -372,34 +374,50 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
       gphi_iterator gsi;
 
       /* Either for VAR itself...  */
-      rtype = get_range_info (var, &minv, &maxv);
+      value_range var_range;
+      RANGE_QUERY (cfun)->range_of_expr (var_range, var);
+      rtype = var_range.kind ();
+      if (!var_range.undefined_p ())
+	{
+	  minv = var_range.lower_bound ();
+	  maxv = var_range.upper_bound ();
+	}
+
       /* Or for PHI results in loop->header where VAR is used as
 	 PHI argument from the loop preheader edge.  */
       for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi))
 	{
 	  gphi *phi = gsi.phi ();
-	  wide_int minc, maxc;
+	  value_range phi_range;
 	  if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var
-	      && (get_range_info (gimple_phi_result (phi), &minc, &maxc)
-		  == VR_RANGE))
+	      && RANGE_QUERY (cfun)->range_of_expr (phi_range,
+						    gimple_phi_result (phi))
+	      && phi_range.kind () == VR_RANGE)
 	    {
 	      if (rtype != VR_RANGE)
 		{
 		  rtype = VR_RANGE;
-		  minv = minc;
-		  maxv = maxc;
+		  minv = phi_range.lower_bound ();
+		  maxv = phi_range.upper_bound ();
 		}
 	      else
 		{
-		  minv = wi::max (minv, minc, sgn);
-		  maxv = wi::min (maxv, maxc, sgn);
+		  minv = wi::max (minv, phi_range.lower_bound (), sgn);
+		  maxv = wi::min (maxv, phi_range.upper_bound (), sgn);
 		  /* If the PHI result range are inconsistent with
 		     the VAR range, give up on looking at the PHI
 		     results.  This can happen if VR_UNDEFINED is
 		     involved.  */
 		  if (wi::gt_p (minv, maxv, sgn))
 		    {
-		      rtype = get_range_info (var, &minv, &maxv);
+		      value_range vr;
+		      RANGE_QUERY (cfun)->range_of_expr (vr, var);
+		      rtype = vr.kind ();
+		      if (!vr.undefined_p ())
+			{
+			  minv = vr.lower_bound ();
+			  maxv = vr.upper_bound ();
+			}
 		      break;
 		    }
 		}
@@ -3545,12 +3563,16 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
 
   if (tree_int_cst_sign_bit (step))
     {
-      wide_int min, max;
+      wide_int max;
+      value_range base_range;
+      if (RANGE_QUERY (cfun)->range_of_expr (base_range, orig_base)
+	  && !base_range.undefined_p ())
+	max = base_range.upper_bound ();
       extreme = fold_convert (unsigned_type, low);
       if (TREE_CODE (orig_base) == SSA_NAME
 	  && TREE_CODE (high) == INTEGER_CST
 	  && INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
-	  && (get_range_info (orig_base, &min, &max) == VR_RANGE
+	  && (base_range.kind () == VR_RANGE
 	      || get_cst_init_from_scev (orig_base, &max, false))
 	  && wi::gts_p (wi::to_wide (high), max))
 	base = wide_int_to_tree (unsigned_type, max);
@@ -3563,12 +3585,16 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
     }
   else
     {
-      wide_int min, max;
+      wide_int min;
+      value_range base_range;
+      if (RANGE_QUERY (cfun)->range_of_expr (base_range, orig_base)
+	  && !base_range.undefined_p ())
+	min = base_range.lower_bound ();
       extreme = fold_convert (unsigned_type, high);
       if (TREE_CODE (orig_base) == SSA_NAME
 	  && TREE_CODE (low) == INTEGER_CST
 	  && INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
-	  && (get_range_info (orig_base, &min, &max) == VR_RANGE
+	  && (base_range.kind () == VR_RANGE
 	      || get_cst_init_from_scev (orig_base, &min, true))
 	  && wi::gts_p (min, wi::to_wide (low)))
 	base = wide_int_to_tree (unsigned_type, min);
@@ -3835,11 +3861,12 @@ infer_loop_bounds_from_signedness (class loop *loop, gimple *stmt)
 
   low = lower_bound_in_type (type, type);
   high = upper_bound_in_type (type, type);
-  wide_int minv, maxv;
-  if (get_range_info (def, &minv, &maxv) == VR_RANGE)
+  value_range r;
+  RANGE_QUERY (cfun)->range_of_expr (r, def);
+  if (r.kind () == VR_RANGE)
     {
-      low = wide_int_to_tree (type, minv);
-      high = wide_int_to_tree (type, maxv);
+      low = wide_int_to_tree (type, r.lower_bound ());
+      high = wide_int_to_tree (type, r.upper_bound ());
     }
 
   record_nonwrapping_iv (loop, base, step, stmt, low, high, false, true);
@@ -4873,7 +4900,6 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
 {
   tree type;
   wide_int minv, maxv, diff, step_wi;
-  enum value_range_kind rtype;
 
   if (TREE_CODE (step) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (var)))
     return false;
@@ -4884,8 +4910,9 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
   if (!def_bb || !dominated_by_p (CDI_DOMINATORS, loop->latch, def_bb))
     return false;
 
-  rtype = get_range_info (var, &minv, &maxv);
-  if (rtype != VR_RANGE)
+  value_range r;
+  RANGE_QUERY (cfun)->range_of_expr (r, var);
+  if (r.kind () != VR_RANGE)
     return false;
 
   /* VAR is a scev whose evolution part is STEP and value range info
@@ -4899,11 +4926,11 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
   type = TREE_TYPE (var);
   if (tree_int_cst_sign_bit (step))
     {
-      diff = minv - wi::to_wide (lower_bound_in_type (type, type));
+      diff = r.lower_bound () - wi::to_wide (lower_bound_in_type (type, type));
       step_wi = - step_wi;
     }
   else
-    diff = wi::to_wide (upper_bound_in_type (type, type)) - maxv;
+    diff = wi::to_wide (upper_bound_in_type (type, type)) - r.upper_bound ();
 
   return (wi::geu_p (diff, step_wi));
 }
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
index 8e8a08bc679..d464c84f164 100644
--- a/gcc/tree-ssa-phiopt.c
+++ b/gcc/tree-ssa-phiopt.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-eh.h"
 #include "gimple-fold.h"
 #include "internal-fn.h"
+#include "gimple-range.h"
 
 static unsigned int tree_ssa_phiopt_worker (bool, bool, bool);
 static bool two_value_replacement (basic_block, basic_block, edge, gphi *,
@@ -684,7 +685,15 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb,
     return false;
 
   wide_int min, max;
-  if (get_range_info (lhs, &min, &max) != VR_RANGE)
+  value_range r;
+  RANGE_QUERY (cfun)->range_of_expr (r, lhs);
+
+  if (r.kind () == VR_RANGE)
+    {
+      min = r.lower_bound ();
+      max = r.upper_bound ();
+    }
+  else
     {
       int prec = TYPE_PRECISION (TREE_TYPE (lhs));
       signop sgn = TYPE_SIGN (TREE_TYPE (lhs));
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index 2d22535af87..870d3cba9ff 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-dce.h"
 #include "tree-cfgcleanup.h"
 #include "alias.h"
+#include "gimple-range.h"
 
 /* Even though this file is called tree-ssa-pre.c, we actually
    implement a bit more than just PRE here.  All of them piggy-back
@@ -3234,16 +3235,18 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
 	  >= TYPE_PRECISION (TREE_TYPE (expr->u.nary->op[0])))
       && SSA_NAME_RANGE_INFO (expr->u.nary->op[0]))
     {
-      wide_int min, max;
-      if (get_range_info (expr->u.nary->op[0], &min, &max) == VR_RANGE
-	  && !wi::neg_p (min, SIGNED)
-	  && !wi::neg_p (max, SIGNED))
+      value_range r;
+      if (RANGE_QUERY (cfun)->range_of_expr (r, expr->u.nary->op[0])
+	  && r.kind () == VR_RANGE
+	  && !wi::neg_p (r.lower_bound (), SIGNED)
+	  && !wi::neg_p (r.upper_bound (), SIGNED))
 	/* Just handle extension and sign-changes of all-positive ranges.  */
-	set_range_info (temp,
-			SSA_NAME_RANGE_TYPE (expr->u.nary->op[0]),
-			wide_int_storage::from (min, TYPE_PRECISION (type),
+	set_range_info (temp, VR_RANGE,
+			wide_int_storage::from (r.lower_bound (),
+						TYPE_PRECISION (type),
 						TYPE_SIGN (type)),
-			wide_int_storage::from (max, TYPE_PRECISION (type),
+			wide_int_storage::from (r.upper_bound (),
+						TYPE_PRECISION (type),
 						TYPE_SIGN (type)));
     }
 
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 32e1632705b..cc098369e2e 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "tree-ssa-reassoc.h"
 #include "tree-ssa-math-opts.h"
+#include "gimple-range.h"
 
 /*  This is a simple global reassociation pass.  It is, in part, based
     on the LLVM pass of the same name (They do some things more/less
@@ -3221,12 +3222,14 @@ optimize_range_tests_to_bit_test (enum tree_code opcode, int first, int length,
 	 amount, then we can merge the entry test in the bit test.  In this
 	 case, if we would need otherwise 2 or more comparisons, then use
 	 the bit test; in the other cases, the threshold is 3 comparisons.  */
-      wide_int min, max;
       bool entry_test_needed;
+      value_range r;
       if (TREE_CODE (exp) == SSA_NAME
-	  && get_range_info (exp, &min, &max) == VR_RANGE
-	  && wi::leu_p (max - min, prec - 1))
+	  && RANGE_QUERY (cfun)->range_of_expr (r, exp)
+	  && r.kind () == VR_RANGE
+	  && wi::leu_p (r.upper_bound () - r.lower_bound (), prec - 1))
 	{
+	  wide_int min = r.lower_bound ();
 	  wide_int ilowi = wi::to_wide (lowi);
 	  if (wi::lt_p (min, ilowi, TYPE_SIGN (TREE_TYPE (lowi))))
 	    {
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index c7b5e2c6e6b..2f85a609107 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -196,7 +196,7 @@ static void handle_builtin_stxncpy_strncat (bool, gimple_stmt_iterator *);
 /* Sets MINMAX to either the constant value or the range VAL is in
    and returns either the constant value or VAL on success or null
    when the range couldn't be determined.  Uses RVALS when nonnull
-   to determine the range, otherwise get_range_info.  */
+   to determine the range, otherwise uses global range info.  */
 
 tree
 get_range (tree val, gimple *stmt, wide_int minmax[2],
@@ -211,9 +211,9 @@ get_range (tree val, gimple *stmt, wide_int minmax[2],
   if (TREE_CODE (val) != SSA_NAME)
     return NULL_TREE;
 
+  value_range vr;
   if (rvals && stmt)
     {
-      value_range vr;
       if (!rvals->range_of_expr (vr, val, stmt))
 	return NULL_TREE;
       value_range_kind rng = vr.kind ();
@@ -225,7 +225,15 @@ get_range (tree val, gimple *stmt, wide_int minmax[2],
       return val;
     }
 
-  value_range_kind rng = get_range_info (val, minmax, minmax + 1);
+  // ?? This entire function should use RANGE_QUERY or GLOBAL_RANGE_QUERY,
+  // instead of doing something different for RVALS and global ranges.
+
+  if (!GLOBAL_RANGE_QUERY->range_of_expr (vr, val) || vr.undefined_p ())
+    return NULL_TREE;
+
+  minmax[0] = wi::to_wide (vr.min ());
+  minmax[1] = wi::to_wide (vr.max ());
+  value_range_kind rng = vr.kind ();
   if (rng == VR_RANGE)
     /* This may be an inverted range whose MINMAX[1] < MINMAX[0].  */
     return val;
@@ -929,7 +937,17 @@ dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals)
 			    rng = VR_UNDEFINED;
 			}
 		      else
-			rng = get_range_info (si->nonzero_chars, &min, &max);
+			{
+			  value_range vr;
+			  GLOBAL_RANGE_QUERY->range_of_expr (vr,
+							     si->nonzero_chars);
+			  rng = vr.kind ();
+			  if (!vr.undefined_p ())
+			    {
+			      min = wi::to_wide (vr.min ());
+			      max = wi::to_wide (vr.max ());
+			    }
+			}
 
 		      if (rng == VR_RANGE || rng == VR_ANTI_RANGE)
 			{
@@ -1809,18 +1827,17 @@ set_strlen_range (tree lhs, wide_int min, wide_int max,
 	}
       else if (TREE_CODE (bound) == SSA_NAME)
 	{
-	  wide_int minbound, maxbound;
-	  // FIXME: Use range_query instead of global ranges.
-	  value_range_kind rng = get_range_info (bound, &minbound, &maxbound);
-	  if (rng == VR_RANGE)
+	  value_range r;
+	  RANGE_QUERY (cfun)->range_of_expr (r, bound);
+	  if (!r.undefined_p ())
 	    {
 	      /* For a bound in a known range, adjust the range determined
 		 above as necessary.  For a bound in some anti-range or
 		 in an unknown range, use the range determined by callers.  */
-	      if (wi::ltu_p (minbound, min))
-		min = minbound;
-	      if (wi::ltu_p (maxbound, max))
-		max = maxbound;
+	      if (wi::ltu_p (r.lower_bound (), min))
+		min = r.lower_bound ();
+	      if (wi::ltu_p (r.upper_bound (), max))
+		max = r.upper_bound ();
 	    }
 	}
     }
@@ -2780,12 +2797,15 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt,
     return false;
 
   wide_int cntrange[2];
+  value_range r;
+  if (!RANGE_QUERY (cfun)->range_of_expr (r, cnt)
+      || r.varying_p ()
+      || r.undefined_p ())
+    return false;
 
-  // FIXME: Use range_query instead of global ranges.
-  enum value_range_kind rng = get_range_info (cnt, cntrange, cntrange + 1);
-  if (rng == VR_RANGE)
-    ;
-  else if (rng == VR_ANTI_RANGE)
+  cntrange[0] = wi::to_wide (r.min ());
+  cntrange[1] = wi::to_wide (r.max ());
+  if (r.kind () == VR_ANTI_RANGE)
     {
       wide_int maxobjsize = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
 
@@ -2800,8 +2820,6 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt,
 	  cntrange[0] = wi::zero (TYPE_PRECISION (TREE_TYPE (cnt)));
 	}
     }
-  else
-    return false;
 
   /* Negative value is the constant string length.  If it's less than
      the lower bound there is no truncation.  Avoid calling get_stridx()
@@ -3923,13 +3941,12 @@ get_len_or_size (gimple *stmt, tree arg, int idx,
 	}
       else if (TREE_CODE (si->nonzero_chars) == SSA_NAME)
 	{
-	  wide_int min, max;
-	  // FIXME: Use range_query instead of global ranges.
-	  value_range_kind rng = get_range_info (si->nonzero_chars, &min, &max);
-	  if (rng == VR_RANGE)
+	  value_range r;
+	  RANGE_QUERY (cfun)->range_of_expr (r, si->nonzero_chars);
+	  if (r.kind () == VR_RANGE)
 	    {
-	      lenrng[0] = min.to_uhwi ();
-	      lenrng[1] = max.to_uhwi ();
+	      lenrng[0] = r.lower_bound ().to_uhwi ();
+	      lenrng[1] = r.upper_bound ().to_uhwi ();
 	      *nulterm = si->full_string_p;
 	    }
 	}
@@ -5301,17 +5318,13 @@ handle_integral_assign (gimple_stmt_iterator *gsi, bool *cleanup_eh,
 		  /* Reading a character before the final '\0'
 		     character.  Just set the value range to ~[0, 0]
 		     if we don't have anything better.  */
-		  wide_int min, max;
-		  signop sign = TYPE_SIGN (lhs_type);
-		  int prec = TYPE_PRECISION (lhs_type);
-		  // FIXME: Use range_query instead of global ranges.
-		  value_range_kind vr = get_range_info (lhs, &min, &max);
-		  if (vr == VR_VARYING
-		      || (vr == VR_RANGE
-			  && min == wi::min_value (prec, sign)
-			  && max == wi::max_value (prec, sign)))
-		    set_range_info (lhs, VR_ANTI_RANGE,
-				    wi::zero (prec), wi::zero (prec));
+		  value_range r;
+		  if (!RANGE_QUERY (cfun)->range_of_expr (r, lhs)
+		      || r.varying_p ())
+		    {
+		      r.set_nonzero (lhs_type);
+		      set_range_info (lhs, r);
+		    }
 		}
 	    }
 	}
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index a0238710e72..514cec1d927 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -43,6 +43,7 @@
 #include "attribs.h"
 #include "tree-ssa.h"
 #include "tree-cfg.h"
+#include "gimple-range.h"
 
 /* The idea behind this analyzer is to generate set constraints from the
    program, then solve the resulting constraints in order to generate the
@@ -6740,7 +6741,9 @@ find_what_p_points_to (tree fndecl, tree p)
   struct ptr_info_def *pi;
   tree lookup_p = p;
   varinfo_t vi;
-  bool nonnull = get_ptr_nonnull (p);
+  value_range vr;
+  GLOBAL_RANGE_QUERY->range_of_expr (vr, p);
+  bool nonnull = vr.nonzero_p ();
 
   /* For parameters, get at the points-to set for the actual parm
      decl.  */
@@ -6758,8 +6761,7 @@ find_what_p_points_to (tree fndecl, tree p)
   pi->pt = find_what_var_points_to (fndecl, vi);
   /* Conservatively set to NULL from PTA (to true). */
   pi->pt.null = 1;
-  /* Preserve pointer nonnull computed by VRP.  See get_ptr_nonnull
-     in gcc/tree-ssaname.c for more information.  */
+  /* Preserve pointer nonnull globally computed.  */
   if (nonnull)
     set_ptr_nonnull (p);
 }
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index f55ce1939ac..b352f68b1b7 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "builtins.h"
 #include "calls.h"
+#include "gimple-range.h"
 
 /* This implements the pass that does predicate aware warning on uses of
    possibly uninitialized variables.  The pass first collects the set of
@@ -1606,11 +1607,14 @@ find_var_cmp_const (pred_chain_union preds, gphi *phi, gimple **flag_def,
 	       flag_var <= [min, max] ->  flag_var < [min, max+1]
 	       flag_var >= [min, max] ->  flag_var > [min-1, max]
 	     if no overflow/wrap.  */
-	  wide_int min, max;
 	  tree type = TREE_TYPE (cond_lhs);
+	  value_range r;
 	  if (!INTEGRAL_TYPE_P (type)
-	      || get_range_info (cond_rhs, &min, &max) != VR_RANGE)
+	      || !RANGE_QUERY (cfun)->range_of_expr (r, cond_rhs)
+	      || r.kind () != VR_RANGE)
 	    continue;
+	  wide_int min = r.lower_bound ();
+	  wide_int max = r.upper_bound ();
 	  if (code == LE_EXPR
 	      && max != wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)))
 	    {
diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
index 7f65c4ce839..225d831003f 100644
--- a/gcc/tree-switch-conversion.c
+++ b/gcc/tree-switch-conversion.c
@@ -50,6 +50,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "target.h"
 #include "tree-into-ssa.h"
 #include "omp-general.h"
+#include "gimple-range.h"
 
 /* ??? For lang_hooks.types.type_for_mode, but is there a word_mode
    type in the GIMPLE type system that is language-independent?  */
@@ -1553,12 +1554,15 @@ bit_test_cluster::emit (tree index_expr, tree index_type,
 
   /* If every possible relative value of the index expression is a valid shift
      amount, then we can merge the entry test in the bit test.  */
-  wide_int min, max;
   bool entry_test_needed;
+  value_range r;
   if (TREE_CODE (index_expr) == SSA_NAME
-      && get_range_info (index_expr, &min, &max) == VR_RANGE
-      && wi::leu_p (max - min, prec - 1))
+      && RANGE_QUERY (cfun)->range_of_expr (r, index_expr)
+      && r.kind () == VR_RANGE
+      && wi::leu_p (r.upper_bound () - r.lower_bound (), prec - 1))
     {
+      wide_int min = r.lower_bound ();
+      wide_int max = r.upper_bound ();
       tree index_type = TREE_TYPE (index_expr);
       minval = fold_convert (index_type, minval);
       wide_int iminval = wi::to_wide (minval);
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index 803de3fc287..99be2314029 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "predict.h"
 #include "tree-vector-builder.h"
 #include "vec-perm-indices.h"
+#include "gimple-range.h"
 
 /* Return true if we have a useful VR_RANGE range for VAR, storing it
    in *MIN_VALUE and *MAX_VALUE if so.  Note the range in the dump files.  */
@@ -55,7 +56,13 @@ along with GCC; see the file COPYING3.  If not see
 static bool
 vect_get_range_info (tree var, wide_int *min_value, wide_int *max_value)
 {
-  value_range_kind vr_type = get_range_info (var, min_value, max_value);
+  value_range vr;
+  RANGE_QUERY (cfun)->range_of_expr (vr, var);
+  if (vr.undefined_p ())
+    vr.set_varying (TREE_TYPE (var));
+  *min_value = wi::to_wide (vr.min ());
+  *max_value = wi::to_wide (vr.max ());
+  value_range_kind vr_type = vr.kind ();
   wide_int nonzero = get_nonzero_bits (var);
   signop sgn = TYPE_SIGN (TREE_TYPE (var));
   if (intersect_range_with_nonzero_bits (vr_type, min_value, max_value,
@@ -3437,13 +3444,14 @@ vect_recog_divmod_pattern (vec_info *vinfo,
       else
 	t3 = t2;
 
-      wide_int oprnd0_min, oprnd0_max;
       int msb = 1;
-      if (get_range_info (oprnd0, &oprnd0_min, &oprnd0_max) == VR_RANGE)
+      value_range r;
+      RANGE_QUERY (cfun)->range_of_expr (r, oprnd0);
+      if (r.kind () == VR_RANGE)
 	{
-	  if (!wi::neg_p (oprnd0_min, TYPE_SIGN (itype)))
+	  if (!wi::neg_p (r.lower_bound (), TYPE_SIGN (itype)))
 	    msb = 0;
-	  else if (wi::neg_p (oprnd0_max, TYPE_SIGN (itype)))
+	  else if (wi::neg_p (r.upper_bound (), TYPE_SIGN (itype)))
 	    msb = -1;
 	}
 
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index b0f1c47f05c..6a723efc0d8 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -228,7 +228,7 @@ intersect_range_with_nonzero_bits (enum value_range_kind vr_type,
 	  vr_type = VR_RANGE;
 	}
     }
-  if (vr_type == VR_RANGE)
+  if (vr_type == VR_RANGE || vr_type == VR_VARYING)
     {
       *max = wi::round_down_for_mask (*max, nonzero_bits);
 
@@ -1717,7 +1717,7 @@ register_edge_assert_for_2 (tree name, edge e,
          simply register the same assert for it.  */
       if (CONVERT_EXPR_CODE_P (rhs_code))
 	{
-	  wide_int rmin, rmax;
+	  value_range vr;
 	  tree rhs1 = gimple_assign_rhs1 (def_stmt);
 	  if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
 	      && TREE_CODE (rhs1) == SSA_NAME
@@ -1739,13 +1739,14 @@ register_edge_assert_for_2 (tree name, edge e,
 	      && int_fits_type_p (val, TREE_TYPE (rhs1))
 	      && ((TYPE_PRECISION (TREE_TYPE (name))
 		   > TYPE_PRECISION (TREE_TYPE (rhs1)))
-		  || (get_range_info (rhs1, &rmin, &rmax) == VR_RANGE
+		  || ((RANGE_QUERY (cfun)->range_of_expr (vr, rhs1)
+		       && vr.kind () == VR_RANGE)
 		      && wi::fits_to_tree_p
-			   (widest_int::from (rmin,
+			   (widest_int::from (vr.lower_bound (),
 					      TYPE_SIGN (TREE_TYPE (rhs1))),
 			    TREE_TYPE (name))
 		      && wi::fits_to_tree_p
-			   (widest_int::from (rmax,
+			   (widest_int::from (vr.upper_bound (),
 					      TYPE_SIGN (TREE_TYPE (rhs1))),
 			    TREE_TYPE (name)))))
 	    add_assert_info (asserts, rhs1, rhs1,
@@ -4631,16 +4632,14 @@ determine_value_range_1 (value_range *vr, tree expr)
     vr->set (expr);
   else
     {
-      value_range_kind kind;
-      wide_int min, max;
+      value_range r;
       /* For SSA names try to extract range info computed by VRP.  Otherwise
 	 fall back to varying.  */
       if (TREE_CODE (expr) == SSA_NAME
 	  && INTEGRAL_TYPE_P (TREE_TYPE (expr))
-	  && (kind = get_range_info (expr, &min, &max)) != VR_VARYING)
-	vr->set (wide_int_to_tree (TREE_TYPE (expr), min),
-		 wide_int_to_tree (TREE_TYPE (expr), max),
-		 kind);
+	  && RANGE_QUERY (cfun)->range_of_expr (r, expr)
+	  && !r.undefined_p ())
+	*vr = r;
       else
 	vr->set_varying (TREE_TYPE (expr));
     }
diff --git a/gcc/tree.c b/gcc/tree.c
index 31ac4245c9c..3d5111628b5 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -68,6 +68,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vector-builder.h"
 #include "gimple-fold.h"
 #include "escaped_string.h"
+#include "gimple-range.h"
 
 /* Tree code classes.  */
 
@@ -13834,8 +13835,8 @@ get_range_pos_neg (tree arg)
 
   if (TREE_CODE (arg) != SSA_NAME)
     return 3;
-  wide_int arg_min, arg_max;
-  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
+  value_range r;
+  while (!GLOBAL_RANGE_QUERY->range_of_expr (r, arg) || r.kind () != VR_RANGE)
     {
       gimple *g = SSA_NAME_DEF_STMT (arg);
       if (is_gimple_assign (g)
@@ -13861,16 +13862,16 @@ get_range_pos_neg (tree arg)
     {
       /* For unsigned values, the "positive" range comes
 	 below the "negative" range.  */
-      if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED))
+      if (!wi::neg_p (wi::sext (r.upper_bound (), prec), SIGNED))
 	return 1;
-      if (wi::neg_p (wi::sext (arg_min, prec), SIGNED))
+      if (wi::neg_p (wi::sext (r.lower_bound (), prec), SIGNED))
 	return 2;
     }
   else
     {
-      if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED))
+      if (!wi::neg_p (wi::sext (r.lower_bound (), prec), SIGNED))
 	return 1;
-      if (wi::neg_p (wi::sext (arg_max, prec), SIGNED))
+      if (wi::neg_p (wi::sext (r.upper_bound (), prec), SIGNED))
 	return 2;
     }
   return 3;
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index a89f0b646ae..02acb46cb20 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -117,14 +117,16 @@ vr_values::get_lattice_entry (const_tree var)
 	     default definitions of PARM_DECLs.  */
 	  if (POINTER_TYPE_P (TREE_TYPE (sym))
 	      && (nonnull_arg_p (sym)
-		  || get_ptr_nonnull (var)))
+		  || (GLOBAL_RANGE_QUERY->range_of_expr (*vr,
+						const_cast <tree> (var))
+		      && vr->nonzero_p ())))
 	    {
 	      vr->set_nonzero (TREE_TYPE (sym));
 	      vr->equiv_clear ();
 	    }
 	  else if (INTEGRAL_TYPE_P (TREE_TYPE (sym)))
 	    {
-	      get_range_info (var, *vr);
+	      GLOBAL_RANGE_QUERY->range_of_expr (*vr, const_cast <tree> (var));
 	      if (vr->undefined_p ())
 		vr->set_varying (TREE_TYPE (sym));
 	    }
@@ -262,7 +264,7 @@ vr_values::update_value_range (const_tree var, value_range_equiv *new_vr)
   if (INTEGRAL_TYPE_P (TREE_TYPE (var)))
     {
       value_range_equiv nr;
-      get_range_info (var, nr);
+      GLOBAL_RANGE_QUERY->range_of_expr (nr, const_cast <tree> (var));
       if (!nr.undefined_p ())
 	new_vr->intersect (&nr);
     }
@@ -3829,13 +3831,13 @@ simplify_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
       || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop))
     return false;
 
-  /* Get the value-range of the inner operand.  Use get_range_info in
+  /* Get the value-range of the inner operand.  Use global ranges in
      case innerop was created during substitute-and-fold.  */
   wide_int imin, imax;
   value_range vr;
   if (!INTEGRAL_TYPE_P (TREE_TYPE (innerop)))
     return false;
-  get_range_info (innerop, vr);
+  RANGE_QUERY (cfun)->range_of_expr (vr, innerop, stmt);
   if (vr.undefined_p () || vr.varying_p ())
     return false;
   innermin = widest_int::from (vr.lower_bound (), TYPE_SIGN (TREE_TYPE (innerop)));
-- 
2.31.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 5/5] Cleanup get_range_info
  2021-05-21 11:39 [PATCH 1/5] Common API for accessing global and on-demand ranges Aldy Hernandez
                   ` (2 preceding siblings ...)
  2021-05-21 11:39 ` [PATCH 4/5] Convert remaining passes to RANGE_QUERY Aldy Hernandez
@ 2021-05-21 11:39 ` Aldy Hernandez
  2021-05-25 16:20   ` Aldy Hernandez
  2021-05-24 16:09 ` [PATCH 1/5] Common API for accessing global and on-demand ranges Aldy Hernandez
  2021-05-24 19:13 ` Martin Sebor
  5 siblings, 1 reply; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-21 11:39 UTC (permalink / raw)
  To: GCC patches, Andrew MacLeod; +Cc: Jeff Law, Martin Sebor, Aldy Hernandez

Now that there is only one user of get_range_info() we can clean this up
to always return a range instead of pairs of wide_ints.

A follow-up patch will inline both get_range_info and get_ptr_nonnull
into its only remaining user.

Tested on x86-64 Linux.

OK?

gcc/ChangeLog:

	* tree-ssanames.c (get_range_info): Merge both copies of
	get_range_info into one that works with irange.
	* tree-ssanames.h (get_range_info): Remove version that works on
	wide_ints.
---
 gcc/tree-ssanames.c | 57 +++++++++++----------------------------------
 gcc/tree-ssanames.h |  2 --
 2 files changed, 14 insertions(+), 45 deletions(-)

diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 51a26d2fce1..5329c0a4187 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -423,58 +423,29 @@ set_range_info (tree name, const value_range &vr)
   set_range_info (name, vr.kind (), min, max);
 }
 
-/* Gets range information MIN, MAX and returns enum value_range_kind
-   corresponding to tree ssa_name NAME.  enum value_range_kind returned
-   is used to determine if MIN and MAX are valid values.  */
+/* Gets range information corresponding to ssa_name NAME and stores it
+   in a value_range VR.  Returns the value_range_kind.  */
 
 enum value_range_kind
-get_range_info (const_tree expr, wide_int *min, wide_int *max)
+get_range_info (const_tree name, irange &vr)
 {
-  gcc_assert (!POINTER_TYPE_P (TREE_TYPE (expr)));
-  gcc_assert (min && max);
-  if (TREE_CODE (expr) == INTEGER_CST)
-    {
-      *min = wi::to_wide (expr);
-      *max = *min;
-      return VR_RANGE;
-    }
-  if (TREE_CODE (expr) != SSA_NAME)
-    return VR_VARYING;
+  tree type = TREE_TYPE (name);
+  gcc_checking_assert (!POINTER_TYPE_P (type));
+  gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
 
-  range_info_def *ri = SSA_NAME_RANGE_INFO (expr);
+  range_info_def *ri = SSA_NAME_RANGE_INFO (name);
 
   /* Return VR_VARYING for SSA_NAMEs with NULL RANGE_INFO or SSA_NAMEs
      with integral types width > 2 * HOST_BITS_PER_WIDE_INT precision.  */
-  if (!ri || (GET_MODE_PRECISION (SCALAR_INT_TYPE_MODE (TREE_TYPE (expr)))
+  if (!ri || (GET_MODE_PRECISION (SCALAR_INT_TYPE_MODE (TREE_TYPE (name)))
 	      > 2 * HOST_BITS_PER_WIDE_INT))
-    return VR_VARYING;
-
-  *min = ri->get_min ();
-  *max = ri->get_max ();
-  return SSA_NAME_RANGE_TYPE (expr);
-}
-
-/* Gets range information corresponding to ssa_name NAME and stores it
-   in a value_range VR.  Returns the value_range_kind.  */
-
-enum value_range_kind
-get_range_info (const_tree name, irange &vr)
-{
-  tree min, max;
-  wide_int wmin, wmax;
-  enum value_range_kind kind = get_range_info (name, &wmin, &wmax);
-
-  if (kind == VR_VARYING)
-    vr.set_varying (TREE_TYPE (name));
-  else if (kind == VR_UNDEFINED)
-    vr.set_undefined ();
+    vr.set_varying (type);
   else
-    {
-      min = wide_int_to_tree (TREE_TYPE (name), wmin);
-      max = wide_int_to_tree (TREE_TYPE (name), wmax);
-      vr.set (min, max, kind);
-    }
-  return kind;
+    vr.set (wide_int_to_tree (type, ri->get_min ()),
+	    wide_int_to_tree (type, ri->get_max ()),
+	    SSA_NAME_RANGE_TYPE (name));
+
+  return vr.kind ();
 }
 
 /* Set nonnull attribute to pointer NAME.  */
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index cce2d2c22e8..166f921f04c 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -71,8 +71,6 @@ extern void set_range_info (tree, enum value_range_kind, const wide_int_ref &,
 			    const wide_int_ref &);
 extern void set_range_info (tree, const value_range &);
 /* Gets the value range from SSA.  */
-extern enum value_range_kind get_range_info (const_tree, wide_int *,
-					     wide_int *);
 extern enum value_range_kind get_range_info (const_tree, irange &);
 extern void set_nonzero_bits (tree, const wide_int_ref &);
 extern wide_int get_nonzero_bits (const_tree);
-- 
2.31.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] Common API for accessing global and on-demand ranges.
  2021-05-21 11:39 [PATCH 1/5] Common API for accessing global and on-demand ranges Aldy Hernandez
                   ` (3 preceding siblings ...)
  2021-05-21 11:39 ` [PATCH 5/5] Cleanup get_range_info Aldy Hernandez
@ 2021-05-24 16:09 ` Aldy Hernandez
  2021-05-25  8:57   ` Richard Biener
  2021-05-24 19:13 ` Martin Sebor
  5 siblings, 1 reply; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-24 16:09 UTC (permalink / raw)
  To: GCC patches, Andrew MacLeod; +Cc: Jeff Law, Martin Sebor



On 5/21/21 1:39 PM, Aldy Hernandez wrote:
> 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:
> 
>    RANGE_QUERY (cfun)->range_of_expr (vr, name, [stmt]);

BTW, we're not wed to the idea of putting the current range object in 
cfun.  The important thing is that the API is consistent across, not 
where it lives.

We're open to suggestions: a global variable, cfun, the pass manager, or 
even a pass property:

   ( PROP_blah | PROP_ranger ), /* properties_required */

I personally like cfun, but we're open to suggestions.

Aldy


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] Common API for accessing global and on-demand ranges.
  2021-05-21 11:39 [PATCH 1/5] Common API for accessing global and on-demand ranges Aldy Hernandez
                   ` (4 preceding siblings ...)
  2021-05-24 16:09 ` [PATCH 1/5] Common API for accessing global and on-demand ranges Aldy Hernandez
@ 2021-05-24 19:13 ` Martin Sebor
  2021-05-25  7:06   ` Aldy Hernandez
  5 siblings, 1 reply; 31+ messages in thread
From: Martin Sebor @ 2021-05-24 19:13 UTC (permalink / raw)
  To: Aldy Hernandez, GCC patches, Andrew MacLeod; +Cc: Martin Sebor

On 5/21/21 5:39 AM, Aldy Hernandez via Gcc-patches wrote:
> 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:
> 
>    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:
> 
>    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 RANGE_QUERY is tied to cfun, 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 cfun, you can use
> GLOBAL_RANGE_QUERY instead of RANGE_QUERY(cfun).  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 ? RANGE_QUERY (cfun) : GLOBAL_RANGE_QUERY;
> 
>    query->range_of_expr (range, expr, [stmt]);
> 
> By default RANGE_QUERY uses 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_RANGE_QUERY.
> 
> 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.

Thanks for the heads up!  This sounds great (and thanks for all
the work converting the existing uses).  Just a few comments on
the changes.

> 
> Tested on x86-64 Linux.
> 
> OK?
> 
> gcc/ChangeLog:
> 
> 	* function.c (allocate_struct_function): Set cfun->x_range_query.
> 	* function.h (struct function): Declare x_range_query.
> 	(RANGE_QUERY): New.
> 	(get_global_range_query): New.
> 	(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            |   4 ++
>   gcc/function.h            |  16 +++++
>   gcc/gimple-range-cache.cc |   1 -
>   gcc/gimple-range.cc       | 130 ++++++++++++++++++++++++++++++++++++++
>   gcc/gimple-range.h        |  60 +++++-------------
>   gcc/gimple-ssa-evrp.c     |   2 +-
>   gcc/tree-vrp.c            |   2 +-
>   gcc/value-query.cc        |   5 ++
>   gcc/value-query.h         |   1 +
>   gcc/vr-values.c           |   2 +-
>   gcc/vr-values.h           |   2 +-
>   11 files changed, 175 insertions(+), 50 deletions(-)
> 
> diff --git a/gcc/function.c b/gcc/function.c
> index fc7b147b5f1..67576950983 100644
> --- a/gcc/function.c
> +++ b/gcc/function.c
> @@ -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
> diff --git a/gcc/function.h b/gcc/function.h
> index 66cfa973808..41b446bfe7c 100644
> --- a/gcc/function.h
> +++ b/gcc/function.h
> @@ -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;
> +

Mostly out of curiosity: why the 'x_' prefix?  (I'm used to seeing
that in the expansion of the option macros but it seems out of place
here.)

>     /* Last statement uid.  */
>     int last_stmt_uid;
>   
> @@ -712,4 +718,14 @@ extern const char *current_function_name (void);
>   
>   extern void used_types_insert (tree);
>   
> +extern range_query *get_global_range_query ();
> +
> +// Returns the currently active range access class.  This is meant to be used
> +// with the `class range_query' API.  When there is no active range class,
> +// global ranges are used.
> +#define RANGE_QUERY(fun) (fun)->x_range_query
> +
> +// As above, but for accessing global ranges between passes.
> +#define GLOBAL_RANGE_QUERY get_global_range_query ()

Unless there's some reason that escapes me, could these be functions
(possibly defined inline) rather than macros?  (They're a lot easier
to work with, such as when I want to trace calls in some way.)

> +
>   #endif  /* GCC_FUNCTION_H */
> diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
> index 2c922e32913..c645d15f5af 100644
> --- a/gcc/gimple-range-cache.cc
> +++ b/gcc/gimple-range-cache.cc
> @@ -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;
>   }
>   
> diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
> index 710bc7f9632..4e1aeee8ed0 100644
> --- a/gcc/gimple-range.cc
> +++ b/gcc/gimple-range.cc
> @@ -1402,3 +1402,133 @@ 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.

I realize this is just being moved from elsewhere but I would suggest
to take this opportunity and also document the effects on the range
argument.

> +
> +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. 

I couldn't help but notice another variation on the dubious ???
yet wide-spread convention:
   https://gcc.gnu.org/pipermail/gcc-patches/2021-May/570442.html

> 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;
> +
> +range_query *
> +get_global_range_query ()
> +{
> +  if (cfun)
> +    return RANGE_QUERY (cfun);
> +
> +  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;
> +}
> +
> +void
> +enable_ranger ()
> +{
> +  gimple_ranger *r;
> +
> +  if (param_evrp_mode & EVRP_MODE_TRACE)
> +    r = new trace_ranger;
> +  else
> +    r = new gimple_ranger;
> +
> +  RANGE_QUERY (cfun) = r;
> +}
> +
> +void
> +disable_ranger (bool export_ranges)
> +{
> +  gimple_ranger *r = (gimple_ranger *) RANGE_QUERY (cfun);
> +
> +  if (export_ranges)
> +    r->export_global_ranges ();
> +
> +  delete r;

The above is a downcast from range_query*, so if the instance is
something else the code won't work correctly and might crash,
right?  Or it might call the wrong function/dtor.  Should there
be a check of some sort to make sure that doesn't happen?

Martin

> +
> +  RANGE_QUERY (cfun) = &global_ranges;
> +}
> diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
> index f33156181bf..1ba073820a6 100644
> --- a/gcc/gimple-range.h
> +++ b/gcc/gimple-range.h
> @@ -53,7 +53,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;
>   protected:
>     bool calc_stmt (irange &r, gimple *s, tree name = NULL_TREE);
>     bool range_of_range_op (irange &r, gimple *s);
> @@ -130,50 +130,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.
>   
> @@ -202,4 +158,18 @@ private:
>   // Temporary external interface to share with vr_values.
>   bool range_of_builtin_call (range_query &query, irange &r, gcall *call);
>   
> +// 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 void enable_ranger ();
> +extern void disable_ranger (bool export_ranges = true);
> +
>   #endif // GCC_GIMPLE_RANGE_STMT_H
> diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c
> index 5f566ae0958..829fdcdaef2 100644
> --- a/gcc/gimple-ssa-evrp.c
> +++ b/gcc/gimple-ssa-evrp.c
> @@ -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");
>         }
>     }
> diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
> index 12e6e6f3e22..b0f1c47f05c 100644
> --- a/gcc/tree-vrp.c
> +++ b/gcc/tree-vrp.c
> @@ -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");
>       }
>   
> diff --git a/gcc/value-query.cc b/gcc/value-query.cc
> index 4bb0897c446..509d2d33cc5 100644
> --- a/gcc/value-query.cc
> +++ b/gcc/value-query.cc
> @@ -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>
> diff --git a/gcc/value-query.h b/gcc/value-query.h
> index e2cbc6852b0..5eff9317ed5 100644
> --- a/gcc/value-query.h
> +++ b/gcc/value-query.h
> @@ -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 ();
> diff --git a/gcc/vr-values.c b/gcc/vr-values.c
> index b1bf53af9e0..a89f0b646ae 100644
> --- a/gcc/vr-values.c
> +++ b/gcc/vr-values.c
> @@ -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;
>   
> diff --git a/gcc/vr-values.h b/gcc/vr-values.h
> index 8c1b2e0a292..81b9131f7f1 100644
> --- a/gcc/vr-values.h
> +++ b/gcc/vr-values.h
> @@ -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,
> 


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 4/5] Convert remaining passes to RANGE_QUERY.
  2021-05-21 11:39 ` [PATCH 4/5] Convert remaining passes to RANGE_QUERY Aldy Hernandez
@ 2021-05-24 19:34   ` Martin Sebor
  2021-05-25  8:47     ` Richard Biener
  2021-05-25  8:48     ` Aldy Hernandez
  2021-05-25 16:19   ` Aldy Hernandez
  1 sibling, 2 replies; 31+ messages in thread
From: Martin Sebor @ 2021-05-24 19:34 UTC (permalink / raw)
  To: Aldy Hernandez, GCC patches, Andrew MacLeod; +Cc: Martin Sebor

On 5/21/21 5:39 AM, Aldy Hernandez via Gcc-patches wrote:
> This patch converts the remaining users of get_range_info and
> get_ptr_nonnull to the range_query API.
> 
> No effort was made to move passes away from VR_ANTI_RANGE, or any other
> use of deprecated methods.  This was a straight up conversion to the new
> API, nothing else.

A question about the uses of the RANGE_QUERY() and GLOBAL_RANGE_QUERY()
macros (hopefully functions): some clients in this patch call one or
the other based on whether cfun is set or null, while others call it
without such testing.  That suggests that the former clients might
be making the assumption that cfun is null while the latter ones
make the opposite assumption that cfun is not null.  It seems that
the code would be safer/more future-proof if it avoided making
these assumptions.

That could be done by introducing a function like this one:

   range_query&
   get_range_query (const function *func = cfun)
   {
     if (func)
       return func->x_range_query;
     return *get_global_range_query ();
   }

This function would be easier to use since clients wouldn't have
to worry about when cfun is null.

Since all clients assume the result is nonnull the function returns
a reference rather a pointer.  (That's presumably also true for
get_global_range_query()).

Martin

> 
> Tested on x86-64 Linux.
> 
> OK?
> 
> gcc/ChangeLog:
> 
> 	* builtins.c (check_nul_terminated_array): Convert to RANGE_QUERY.
> 	(expand_builtin_strnlen): Same.
> 	(determine_block_size): Same.
> 	* fold-const.c (expr_not_equal_to): Same.
> 	* gimple-fold.c (size_must_be_zero_p): Same.
> 	* gimple-match-head.c: Include gimple-range.h.
> 	* gimple-pretty-print.c (dump_ssaname_info): Convert to RANGE_QUERY.
> 	* gimple-ssa-warn-restrict.c
> 	(builtin_memref::extend_offset_range): Same.
> 	* graphite-sese-to-poly.c (add_param_constraints): Same.
> 	* internal-fn.c (get_min_precision): Same.
> 	* ipa-fnsummary.c (set_switch_stmt_execution_predicate): Same.
> 	* ipa-prop.c (ipa_compute_jump_functions_for_edge): Same.
> 	* match.pd: Same.
> 	* tree-data-ref.c (split_constant_offset): Same.
> 	(dr_step_indicator): Same.
> 	* tree-dfa.c (get_ref_base_and_extent): Same.
> 	* tree-scalar-evolution.c (iv_can_overflow_p): Same.
> 	* tree-ssa-loop-niter.c (refine_value_range_using_guard): Same.
> 	(determine_value_range): Same.
> 	(record_nonwrapping_iv): Same.
> 	(infer_loop_bounds_from_signedness): Same.
> 	(scev_var_range_cant_overflow): Same.
> 	* tree-ssa-phiopt.c (two_value_replacement): Same.
> 	* tree-ssa-pre.c (insert_into_preds_of_block): Same.
> 	* tree-ssa-reassoc.c (optimize_range_tests_to_bit_test): Same.
> 	* tree-ssa-strlen.c (handle_builtin_stxncpy_strncat): Same.
> 	(get_range): Same.
> 	(dump_strlen_info): Same.
> 	(set_strlen_range): Same.
> 	(maybe_diag_stxncpy_trunc): Same.
> 	(get_len_or_size): Same.
> 	(handle_integral_assign): Same.
> 	* tree-ssa-structalias.c (find_what_p_points_to): Same.
> 	* tree-ssa-uninit.c (find_var_cmp_const): Same.
> 	* tree-switch-conversion.c (bit_test_cluster::emit): Same.
> 	* tree-vect-patterns.c (vect_get_range_info): Same.
> 	(vect_recog_divmod_pattern): Same.
> 	* tree-vrp.c (intersect_range_with_nonzero_bits): Same.
> 	(register_edge_assert_for_2): Same.
> 	(determine_value_range_1): Same.
> 	* tree.c (get_range_pos_neg): Same.
> 	* vr-values.c (vr_values::get_lattice_entry): Same.
> 	(vr_values::update_value_range): Same.
> 	(simplify_conversion_using_ranges): Same.
> ---
>   gcc/builtins.c                 | 40 ++++++++++------
>   gcc/fold-const.c               |  8 +++-
>   gcc/gimple-fold.c              |  7 ++-
>   gcc/gimple-match-head.c        |  1 +
>   gcc/gimple-pretty-print.c      | 12 ++++-
>   gcc/gimple-ssa-warn-restrict.c |  8 +++-
>   gcc/graphite-sese-to-poly.c    |  9 +++-
>   gcc/internal-fn.c              | 14 +++---
>   gcc/ipa-fnsummary.c            | 11 ++++-
>   gcc/ipa-prop.c                 | 16 +++----
>   gcc/match.pd                   | 19 ++++++--
>   gcc/tree-data-ref.c            | 24 ++++++++--
>   gcc/tree-dfa.c                 | 14 +++++-
>   gcc/tree-scalar-evolution.c    | 13 +++++-
>   gcc/tree-ssa-loop-niter.c      | 81 +++++++++++++++++++++-----------
>   gcc/tree-ssa-phiopt.c          | 11 ++++-
>   gcc/tree-ssa-pre.c             | 19 ++++----
>   gcc/tree-ssa-reassoc.c         |  9 ++--
>   gcc/tree-ssa-strlen.c          | 85 ++++++++++++++++++++--------------
>   gcc/tree-ssa-structalias.c     |  8 ++--
>   gcc/tree-ssa-uninit.c          |  8 +++-
>   gcc/tree-switch-conversion.c   | 10 ++--
>   gcc/tree-vect-patterns.c       | 18 +++++--
>   gcc/tree-vrp.c                 | 21 ++++-----
>   gcc/tree.c                     | 13 +++---
>   gcc/vr-values.c                | 12 +++--
>   26 files changed, 332 insertions(+), 159 deletions(-)
> 
> diff --git a/gcc/builtins.c b/gcc/builtins.c
> index e1b284846b1..deb7c083315 100644
> --- a/gcc/builtins.c
> +++ b/gcc/builtins.c
> @@ -79,6 +79,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "tree-outof-ssa.h"
>   #include "attr-fnspec.h"
>   #include "demangle.h"
> +#include "gimple-range.h"
>   
>   struct target_builtins default_target_builtins;
>   #if SWITCHABLE_TARGET
> @@ -1214,14 +1215,15 @@ check_nul_terminated_array (tree expr, tree src,
>     wide_int bndrng[2];
>     if (bound)
>       {
> -      if (TREE_CODE (bound) == INTEGER_CST)
> -	bndrng[0] = bndrng[1] = wi::to_wide (bound);
> -      else
> -	{
> -	  value_range_kind rng = get_range_info (bound, bndrng, bndrng + 1);
> -	  if (rng != VR_RANGE)
> -	    return true;
> -	}
> +      value_range r;
> +
> +      GLOBAL_RANGE_QUERY->range_of_expr (r, bound);
> +
> +      if (r.kind () != VR_RANGE)
> +	return true;
> +
> +      bndrng[0] = r.lower_bound ();
> +      bndrng[1] = r.upper_bound ();
>   
>         if (exact)
>   	{
> @@ -3827,9 +3829,12 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
>       return NULL_RTX;
>   
>     wide_int min, max;
> -  enum value_range_kind rng = get_range_info (bound, &min, &max);
> -  if (rng != VR_RANGE)
> +  value_range r;
> +  GLOBAL_RANGE_QUERY->range_of_expr (r, bound);
> +  if (r.kind () != VR_RANGE)
>       return NULL_RTX;
> +  min = r.lower_bound ();
> +  max = r.upper_bound ();
>   
>     if (!len || TREE_CODE (len) != INTEGER_CST)
>       {
> @@ -3897,7 +3902,16 @@ determine_block_size (tree len, rtx len_rtx,
>   	*probable_max_size = *max_size = GET_MODE_MASK (GET_MODE (len_rtx));
>   
>         if (TREE_CODE (len) == SSA_NAME)
> -	range_type = get_range_info (len, &min, &max);
> +	{
> +	  value_range r;
> +	  GLOBAL_RANGE_QUERY->range_of_expr (r, len);
> +	  range_type = r.kind ();
> +	  if (range_type != VR_UNDEFINED)
> +	    {
> +	      min = wi::to_wide (r.min ());
> +	      max = wi::to_wide (r.max ());
> +	    }
> +	}
>         if (range_type == VR_RANGE)
>   	{
>   	  if (wi::fits_uhwi_p (min) && *min_size < min.to_uhwi ())
> @@ -4914,8 +4928,8 @@ check_read_access (tree exp, tree src, tree bound /* = NULL_TREE */,
>   /* If STMT is a call to an allocation function, returns the constant
>      maximum size of the object allocated by the call represented as
>      sizetype.  If nonnull, sets RNG1[] to the range of the size.
> -   When nonnull, uses RVALS for range information, otherwise calls
> -   get_range_info to get it.
> +   When nonnull, uses RVALS for range information, otherwise gets global
> +   range info.
>      Returns null when STMT is not a call to a valid allocation function.  */
>   
>   tree
> diff --git a/gcc/fold-const.c b/gcc/fold-const.c
> index 5a41524702b..d680ba1442f 100644
> --- a/gcc/fold-const.c
> +++ b/gcc/fold-const.c
> @@ -83,6 +83,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "tree-vector-builder.h"
>   #include "vec-perm-indices.h"
>   #include "asan.h"
> +#include "gimple-range.h"
>   
>   /* Nonzero if we are folding constants inside an initializer; zero
>      otherwise.  */
> @@ -10686,7 +10687,12 @@ expr_not_equal_to (tree t, const wide_int &w)
>       case SSA_NAME:
>         if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
>   	return false;
> -      get_range_info (t, vr);
> +
> +      if (cfun)
> +	RANGE_QUERY (cfun)->range_of_expr (vr, t);
> +      else
> +	GLOBAL_RANGE_QUERY->range_of_expr (vr, t);
> +
>         if (!vr.undefined_p ()
>   	  && !vr.contains_p (wide_int_to_tree (TREE_TYPE (t), w)))
>   	return true;
> diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
> index 68717cf1542..228fa1b357f 100644
> --- a/gcc/gimple-fold.c
> +++ b/gcc/gimple-fold.c
> @@ -873,7 +873,12 @@ size_must_be_zero_p (tree size)
>     value_range valid_range (build_int_cst (type, 0),
>   			   wide_int_to_tree (type, ssize_max));
>     value_range vr;
> -  get_range_info (size, vr);
> +  if (cfun)
> +    RANGE_QUERY (cfun)->range_of_expr (vr, size);
> +  else
> +    GLOBAL_RANGE_QUERY->range_of_expr (vr, size);
> +  if (vr.undefined_p ())
> +    vr.set_varying (TREE_TYPE (size));
>     vr.intersect (&valid_range);
>     return vr.zero_p ();
>   }
> diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c
> index b084a31572a..7112c116835 100644
> --- a/gcc/gimple-match-head.c
> +++ b/gcc/gimple-match-head.c
> @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "tree-eh.h"
>   #include "dbgcnt.h"
>   #include "tm.h"
> +#include "gimple-range.h"
>   
>   /* Forward declarations of the private auto-generated matchers.
>      They expect valueized operands in canonical order and do not
> diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
> index 0ef01e6420b..62d895d1625 100644
> --- a/gcc/gimple-pretty-print.c
> +++ b/gcc/gimple-pretty-print.c
> @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "attribs.h"
>   #include "asan.h"
>   #include "cfgloop.h"
> +#include "gimple-range.h"
>   
>   /* Disable warnings about quoting issues in the pp_xxx calls below
>      that (intentionally) don't follow GCC diagnostic conventions.  */
> @@ -2263,8 +2264,17 @@ dump_ssaname_info (pretty_printer *buffer, tree node, int spc)
>         && SSA_NAME_RANGE_INFO (node))
>       {
>         wide_int min, max, nonzero_bits;
> -      value_range_kind range_type = get_range_info (node, &min, &max);
> +      value_range r;
>   
> +      GLOBAL_RANGE_QUERY->range_of_expr (r, node);
> +      value_range_kind range_type = r.kind ();
> +      if (!r.undefined_p ())
> +	{
> +	  min = wi::to_wide (r.min ());
> +	  max = wi::to_wide (r.max ());
> +	}
> +
> +      // FIXME: Use irange::dump() instead.
>         if (range_type == VR_VARYING)
>   	pp_printf (buffer, "# RANGE VR_VARYING");
>         else if (range_type == VR_RANGE || range_type == VR_ANTI_RANGE)
> diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
> index ad37f20afaa..a59731c2bc2 100644
> --- a/gcc/gimple-ssa-warn-restrict.c
> +++ b/gcc/gimple-ssa-warn-restrict.c
> @@ -349,7 +349,13 @@ builtin_memref::extend_offset_range (tree offset)
>   	  /* There is a global version here because
>   	     check_bounds_or_overlap may be called from gimple
>   	     fold during gimple lowering.  */
> -	  rng = get_range_info (offset, &min, &max);
> +	  RANGE_QUERY (cfun)->range_of_expr (vr, offset, stmt);
> +	  rng = vr.kind ();
> +	  if (!vr.undefined_p ())
> +	    {
> +	      min = wi::to_wide (vr.min ());
> +	      max = wi::to_wide (vr.max ());
> +	    }
>   	}
>         if (rng == VR_ANTI_RANGE && wi::lts_p (max, min))
>   	{
> diff --git a/gcc/graphite-sese-to-poly.c b/gcc/graphite-sese-to-poly.c
> index eebf2e02cfc..2d332f69a92 100644
> --- a/gcc/graphite-sese-to-poly.c
> +++ b/gcc/graphite-sese-to-poly.c
> @@ -418,13 +418,18 @@ static void
>   add_param_constraints (scop_p scop, graphite_dim_t p, tree parameter)
>   {
>     tree type = TREE_TYPE (parameter);
> +  value_range r;
>     wide_int min, max;
>   
>     gcc_assert (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type));
>   
>     if (INTEGRAL_TYPE_P (type)
> -      && get_range_info (parameter, &min, &max) == VR_RANGE)
> -    ;
> +      && RANGE_QUERY (cfun)->range_of_expr (r, parameter)
> +      && !r.undefined_p ())
> +    {
> +      min = r.lower_bound ();
> +      max = r.upper_bound ();
> +    }
>     else
>       {
>         min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
> diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
> index d209a52f823..dd1f204863e 100644
> --- a/gcc/internal-fn.c
> +++ b/gcc/internal-fn.c
> @@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "ssa-iterators.h"
>   #include "explow.h"
>   #include "rtl-iter.h"
> +#include "gimple-range.h"
>   
>   /* The names of each internal function, indexed by function number.  */
>   const char *const internal_fn_name_array[] = {
> @@ -680,8 +681,9 @@ get_min_precision (tree arg, signop sign)
>       }
>     if (TREE_CODE (arg) != SSA_NAME)
>       return prec + (orig_sign != sign);
> -  wide_int arg_min, arg_max;
> -  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
> +  value_range r;
> +  while (!GLOBAL_RANGE_QUERY->range_of_expr (r, arg)
> +	 || r.kind () != VR_RANGE)
>       {
>         gimple *g = SSA_NAME_DEF_STMT (arg);
>         if (is_gimple_assign (g)
> @@ -709,14 +711,14 @@ get_min_precision (tree arg, signop sign)
>       }
>     if (sign == TYPE_SIGN (TREE_TYPE (arg)))
>       {
> -      int p1 = wi::min_precision (arg_min, sign);
> -      int p2 = wi::min_precision (arg_max, sign);
> +      int p1 = wi::min_precision (r.lower_bound (), sign);
> +      int p2 = wi::min_precision (r.upper_bound (), sign);
>         p1 = MAX (p1, p2);
>         prec = MIN (prec, p1);
>       }
> -  else if (sign == UNSIGNED && !wi::neg_p (arg_min, SIGNED))
> +  else if (sign == UNSIGNED && !wi::neg_p (r.lower_bound (), SIGNED))
>       {
> -      int p = wi::min_precision (arg_max, UNSIGNED);
> +      int p = wi::min_precision (r.upper_bound (), UNSIGNED);
>         prec = MIN (prec, p);
>       }
>     return prec + (orig_sign != sign);
> diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
> index 4e5be812734..299d7fc1f60 100644
> --- a/gcc/ipa-fnsummary.c
> +++ b/gcc/ipa-fnsummary.c
> @@ -85,6 +85,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "attribs.h"
>   #include "tree-into-ssa.h"
>   #include "symtab-clones.h"
> +#include "gimple-range.h"
>   
>   /* Summaries.  */
>   fast_function_summary <ipa_fn_summary *, va_gc> *ipa_fn_summaries;
> @@ -1687,8 +1688,14 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
>     int bound_limit = opt_for_fn (fbi->node->decl,
>   				param_ipa_max_switch_predicate_bounds);
>     int bound_count = 0;
> -  wide_int vr_wmin, vr_wmax;
> -  value_range_kind vr_type = get_range_info (op, &vr_wmin, &vr_wmax);
> +  value_range vr;
> +
> +  RANGE_QUERY (cfun)->range_of_expr (vr, op);
> +  if (vr.undefined_p ())
> +    vr.set_varying (TREE_TYPE (op));
> +  value_range_kind vr_type = vr.kind ();
> +  wide_int vr_wmin = wi::to_wide (vr.min ());
> +  wide_int vr_wmax = wi::to_wide (vr.max ());
>   
>     FOR_EACH_EDGE (e, ei, bb->succs)
>       {
> diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
> index 0591ef1b569..02f422bdbf3 100644
> --- a/gcc/ipa-prop.c
> +++ b/gcc/ipa-prop.c
> @@ -55,6 +55,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "options.h"
>   #include "symtab-clones.h"
>   #include "attr-fnspec.h"
> +#include "gimple-range.h"
>   
>   /* Function summary where the parameter infos are actually stored. */
>   ipa_node_params_t *ipa_node_params_sum = NULL;
> @@ -2237,6 +2238,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
>     gcall *call = cs->call_stmt;
>     int n, arg_num = gimple_call_num_args (call);
>     bool useful_context = false;
> +  value_range vr;
>   
>     if (arg_num == 0 || args->jump_functions)
>       return;
> @@ -2274,7 +2276,8 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
>   
>   	  if (TREE_CODE (arg) == SSA_NAME
>   	      && param_type
> -	      && get_ptr_nonnull (arg))
> +	      && RANGE_QUERY (cfun)->range_of_expr (vr, arg)
> +	      && vr.nonzero_p ())
>   	    addr_nonzero = true;
>   	  else if (tree_single_nonzero_warnv_p (arg, &strict_overflow))
>   	    addr_nonzero = true;
> @@ -2289,19 +2292,14 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
>   	}
>         else
>   	{
> -	  wide_int min, max;
> -	  value_range_kind kind;
>   	  if (TREE_CODE (arg) == SSA_NAME
>   	      && param_type
> -	      && (kind = get_range_info (arg, &min, &max))
> -	      && (kind == VR_RANGE || kind == VR_ANTI_RANGE))
> +	      && RANGE_QUERY (cfun)->range_of_expr (vr, arg)
> +	      && !vr.undefined_p ())
>   	    {
>   	      value_range resvr;
> -	      value_range tmpvr (wide_int_to_tree (TREE_TYPE (arg), min),
> -				 wide_int_to_tree (TREE_TYPE (arg), max),
> -				 kind);
>   	      range_fold_unary_expr (&resvr, NOP_EXPR, param_type,
> -				     &tmpvr, TREE_TYPE (arg));
> +				     &vr, TREE_TYPE (arg));
>   	      if (!resvr.undefined_p () && !resvr.varying_p ())
>   		ipa_set_jfunc_vr (jfunc, &resvr);
>   	      else
> diff --git a/gcc/match.pd b/gcc/match.pd
> index cdb87636951..9dddf5ebd0a 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -663,11 +663,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>       (with
>        {
>          bool overflowed = true;
> -       wide_int wmin0, wmax0, wmin1, wmax1;
> +       value_range vr0, vr1;
>          if (INTEGRAL_TYPE_P (type)
> -	   && get_range_info (@0, &wmin0, &wmax0) == VR_RANGE
> -	   && get_range_info (@1, &wmin1, &wmax1) == VR_RANGE)
> +	   && GLOBAL_RANGE_QUERY->range_of_expr (vr0, @0)
> +	   && GLOBAL_RANGE_QUERY->range_of_expr (vr1, @1)
> +	   && vr0.kind () == VR_RANGE
> +	   && vr1.kind () == VR_RANGE)
>   	 {
> +	   wide_int wmin0 = vr0.lower_bound ();
> +	   wide_int wmax0 = vr0.upper_bound ();
> +	   wide_int wmin1 = vr1.lower_bound ();
> +	   wide_int wmax1 = vr1.upper_bound ();
>   	   /* If the multiplication can't overflow/wrap around, then
>   	      it can be optimized too.  */
>   	   wi::overflow_type min_ovf, max_ovf;
> @@ -2509,9 +2515,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>   	  = wide_int::from (wi::to_wide (@1), TYPE_PRECISION (inner_type),
>   			    TYPE_SIGN (inner_type));
>   
> -        wide_int wmin0, wmax0;
> -        if (get_range_info (@0, &wmin0, &wmax0) == VR_RANGE)
> +	value_range vr;
> +	if (GLOBAL_RANGE_QUERY->range_of_expr (vr, @0)
> +	    && vr.kind () == VR_RANGE)
>             {
> +	    wide_int wmin0 = vr.lower_bound ();
> +	    wide_int wmax0 = vr.upper_bound ();
>               wi::add (wmin0, w1, TYPE_SIGN (inner_type), &min_ovf);
>               wi::add (wmax0, w1, TYPE_SIGN (inner_type), &max_ovf);
>             }
> diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
> index e6dd5f15bed..5ba41e2c73d 100644
> --- a/gcc/tree-data-ref.c
> +++ b/gcc/tree-data-ref.c
> @@ -1035,14 +1035,23 @@ split_constant_offset (tree exp, tree *var, tree *off, value_range *exp_range,
>         *exp_range = type;
>         if (code == SSA_NAME)
>   	{
> -	  wide_int var_min, var_max;
> -	  value_range_kind vr_kind = get_range_info (exp, &var_min, &var_max);
> +	  value_range vr;
> +	  RANGE_QUERY (cfun)->range_of_expr (vr, exp);
> +	  if (vr.undefined_p ())
> +	    vr.set_varying (TREE_TYPE (exp));
> +	  wide_int var_min = wi::to_wide (vr.min ());
> +	  wide_int var_max = wi::to_wide (vr.max ());
> +	  value_range_kind vr_kind = vr.kind ();
>   	  wide_int var_nonzero = get_nonzero_bits (exp);
>   	  vr_kind = intersect_range_with_nonzero_bits (vr_kind,
>   						       &var_min, &var_max,
>   						       var_nonzero,
>   						       TYPE_SIGN (type));
> -	  if (vr_kind == VR_RANGE)
> +	  /* This check for VR_VARYING is here because the old code
> +	     using get_range_info would return VR_RANGE for the entire
> +	     domain, instead of VR_VARYING.  The new code normalizes
> +	     full-domain ranges to VR_VARYING.  */
> +	  if (vr_kind == VR_RANGE || vr_kind == VR_VARYING)
>   	    *exp_range = value_range (type, var_min, var_max);
>   	}
>       }
> @@ -6298,12 +6307,19 @@ dr_step_indicator (struct data_reference *dr, int useful_min)
>   
>         /* Get the range of values that the unconverted step actually has.  */
>         wide_int step_min, step_max;
> +      value_range vr;
>         if (TREE_CODE (step) != SSA_NAME
> -	  || get_range_info (step, &step_min, &step_max) != VR_RANGE)
> +	  || !RANGE_QUERY (cfun)->range_of_expr (vr, step)
> +	  || vr.kind () != VR_RANGE)
>   	{
>   	  step_min = wi::to_wide (TYPE_MIN_VALUE (type));
>   	  step_max = wi::to_wide (TYPE_MAX_VALUE (type));
>   	}
> +      else
> +	{
> +	  step_min = vr.lower_bound ();
> +	  step_max = vr.upper_bound ();
> +	}
>   
>         /* Check whether the unconverted step has an acceptable range.  */
>         signop sgn = TYPE_SIGN (type);
> diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
> index 0482b05e26c..e9cf4bfa706 100644
> --- a/gcc/tree-dfa.c
> +++ b/gcc/tree-dfa.c
> @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "gimple-iterator.h"
>   #include "gimple-walk.h"
>   #include "tree-dfa.h"
> +#include "gimple-range.h"
>   
>   /* Build and maintain data flow information for trees.  */
>   
> @@ -530,14 +531,23 @@ get_ref_base_and_extent (tree exp, poly_int64_pod *poffset,
>   		   index.  */
>   		seen_variable_array_ref = true;
>   
> -		wide_int min, max;
> +		value_range vr;
> +		range_query *query;
> +		if (cfun)
> +		  query = RANGE_QUERY (cfun);
> +		else
> +		  query = GLOBAL_RANGE_QUERY;
> +
>   		if (TREE_CODE (index) == SSA_NAME
>   		    && (low_bound = array_ref_low_bound (exp),
>   			poly_int_tree_p (low_bound))
>   		    && (unit_size = array_ref_element_size (exp),
>   			TREE_CODE (unit_size) == INTEGER_CST)
> -		    && get_range_info (index, &min, &max) == VR_RANGE)
> +		    && query->range_of_expr (vr, index)
> +		    && vr.kind () == VR_RANGE)
>   		  {
> +		    wide_int min = vr.lower_bound ();
> +		    wide_int max = vr.upper_bound ();
>   		    poly_offset_int lbound = wi::to_poly_offset (low_bound);
>   		    /* Try to constrain maxsize with range information.  */
>   		    offset_int omax
> diff --git a/gcc/tree-scalar-evolution.c b/gcc/tree-scalar-evolution.c
> index ff052be1021..f0f28f26042 100644
> --- a/gcc/tree-scalar-evolution.c
> +++ b/gcc/tree-scalar-evolution.c
> @@ -3039,18 +3039,27 @@ iv_can_overflow_p (class loop *loop, tree type, tree base, tree step)
>     widest_int nit;
>     wide_int base_min, base_max, step_min, step_max, type_min, type_max;
>     signop sgn = TYPE_SIGN (type);
> +  value_range r;
>   
>     if (integer_zerop (step))
>       return false;
>   
>     if (!INTEGRAL_TYPE_P (TREE_TYPE (base))
> -      || get_range_info (base, &base_min, &base_max) != VR_RANGE)
> +      || !RANGE_QUERY (cfun)->range_of_expr (r, base)
> +      || r.kind () != VR_RANGE)
>       return true;
>   
> +  base_min = r.lower_bound ();
> +  base_max = r.upper_bound ();
> +
>     if (!INTEGRAL_TYPE_P (TREE_TYPE (step))
> -      || get_range_info (step, &step_min, &step_max) != VR_RANGE)
> +      || !RANGE_QUERY (cfun)->range_of_expr (r, step)
> +      || r.kind () != VR_RANGE)
>       return true;
>   
> +  step_min = r.lower_bound ();
> +  step_max = r.upper_bound ();
> +
>     if (!get_max_loop_iterations (loop, &nit))
>       return true;
>   
> diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
> index 3817ec423e7..bfbb11c59c5 100644
> --- a/gcc/tree-ssa-loop-niter.c
> +++ b/gcc/tree-ssa-loop-niter.c
> @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "tree-chrec.h"
>   #include "tree-scalar-evolution.h"
>   #include "tree-dfa.h"
> +#include "gimple-range.h"
>   
>   
>   /* The maximum number of dominator BBs we search for conditions
> @@ -121,7 +122,6 @@ refine_value_range_using_guard (tree type, tree var,
>     tree varc0, varc1, ctype;
>     mpz_t offc0, offc1;
>     mpz_t mint, maxt, minc1, maxc1;
> -  wide_int minv, maxv;
>     bool no_wrap = nowrap_type_p (type);
>     bool c0_ok, c1_ok;
>     signop sgn = TYPE_SIGN (type);
> @@ -221,6 +221,7 @@ refine_value_range_using_guard (tree type, tree var,
>     get_type_static_bounds (type, mint, maxt);
>     mpz_init (minc1);
>     mpz_init (maxc1);
> +  value_range r;
>     /* Setup range information for varc1.  */
>     if (integer_zerop (varc1))
>       {
> @@ -229,11 +230,12 @@ refine_value_range_using_guard (tree type, tree var,
>       }
>     else if (TREE_CODE (varc1) == SSA_NAME
>   	   && INTEGRAL_TYPE_P (type)
> -	   && get_range_info (varc1, &minv, &maxv) == VR_RANGE)
> +	   && RANGE_QUERY (cfun)->range_of_expr (r, varc1)
> +	   && r.kind () == VR_RANGE)
>       {
> -      gcc_assert (wi::le_p (minv, maxv, sgn));
> -      wi::to_mpz (minv, minc1, sgn);
> -      wi::to_mpz (maxv, maxc1, sgn);
> +      gcc_assert (wi::le_p (r.lower_bound (), r.upper_bound (), sgn));
> +      wi::to_mpz (r.lower_bound (), minc1, sgn);
> +      wi::to_mpz (r.upper_bound (), maxc1, sgn);
>       }
>     else
>       {
> @@ -372,34 +374,50 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
>         gphi_iterator gsi;
>   
>         /* Either for VAR itself...  */
> -      rtype = get_range_info (var, &minv, &maxv);
> +      value_range var_range;
> +      RANGE_QUERY (cfun)->range_of_expr (var_range, var);
> +      rtype = var_range.kind ();
> +      if (!var_range.undefined_p ())
> +	{
> +	  minv = var_range.lower_bound ();
> +	  maxv = var_range.upper_bound ();
> +	}
> +
>         /* Or for PHI results in loop->header where VAR is used as
>   	 PHI argument from the loop preheader edge.  */
>         for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi))
>   	{
>   	  gphi *phi = gsi.phi ();
> -	  wide_int minc, maxc;
> +	  value_range phi_range;
>   	  if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var
> -	      && (get_range_info (gimple_phi_result (phi), &minc, &maxc)
> -		  == VR_RANGE))
> +	      && RANGE_QUERY (cfun)->range_of_expr (phi_range,
> +						    gimple_phi_result (phi))
> +	      && phi_range.kind () == VR_RANGE)
>   	    {
>   	      if (rtype != VR_RANGE)
>   		{
>   		  rtype = VR_RANGE;
> -		  minv = minc;
> -		  maxv = maxc;
> +		  minv = phi_range.lower_bound ();
> +		  maxv = phi_range.upper_bound ();
>   		}
>   	      else
>   		{
> -		  minv = wi::max (minv, minc, sgn);
> -		  maxv = wi::min (maxv, maxc, sgn);
> +		  minv = wi::max (minv, phi_range.lower_bound (), sgn);
> +		  maxv = wi::min (maxv, phi_range.upper_bound (), sgn);
>   		  /* If the PHI result range are inconsistent with
>   		     the VAR range, give up on looking at the PHI
>   		     results.  This can happen if VR_UNDEFINED is
>   		     involved.  */
>   		  if (wi::gt_p (minv, maxv, sgn))
>   		    {
> -		      rtype = get_range_info (var, &minv, &maxv);
> +		      value_range vr;
> +		      RANGE_QUERY (cfun)->range_of_expr (vr, var);
> +		      rtype = vr.kind ();
> +		      if (!vr.undefined_p ())
> +			{
> +			  minv = vr.lower_bound ();
> +			  maxv = vr.upper_bound ();
> +			}
>   		      break;
>   		    }
>   		}
> @@ -3545,12 +3563,16 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
>   
>     if (tree_int_cst_sign_bit (step))
>       {
> -      wide_int min, max;
> +      wide_int max;
> +      value_range base_range;
> +      if (RANGE_QUERY (cfun)->range_of_expr (base_range, orig_base)
> +	  && !base_range.undefined_p ())
> +	max = base_range.upper_bound ();
>         extreme = fold_convert (unsigned_type, low);
>         if (TREE_CODE (orig_base) == SSA_NAME
>   	  && TREE_CODE (high) == INTEGER_CST
>   	  && INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
> -	  && (get_range_info (orig_base, &min, &max) == VR_RANGE
> +	  && (base_range.kind () == VR_RANGE
>   	      || get_cst_init_from_scev (orig_base, &max, false))
>   	  && wi::gts_p (wi::to_wide (high), max))
>   	base = wide_int_to_tree (unsigned_type, max);
> @@ -3563,12 +3585,16 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
>       }
>     else
>       {
> -      wide_int min, max;
> +      wide_int min;
> +      value_range base_range;
> +      if (RANGE_QUERY (cfun)->range_of_expr (base_range, orig_base)
> +	  && !base_range.undefined_p ())
> +	min = base_range.lower_bound ();
>         extreme = fold_convert (unsigned_type, high);
>         if (TREE_CODE (orig_base) == SSA_NAME
>   	  && TREE_CODE (low) == INTEGER_CST
>   	  && INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
> -	  && (get_range_info (orig_base, &min, &max) == VR_RANGE
> +	  && (base_range.kind () == VR_RANGE
>   	      || get_cst_init_from_scev (orig_base, &min, true))
>   	  && wi::gts_p (min, wi::to_wide (low)))
>   	base = wide_int_to_tree (unsigned_type, min);
> @@ -3835,11 +3861,12 @@ infer_loop_bounds_from_signedness (class loop *loop, gimple *stmt)
>   
>     low = lower_bound_in_type (type, type);
>     high = upper_bound_in_type (type, type);
> -  wide_int minv, maxv;
> -  if (get_range_info (def, &minv, &maxv) == VR_RANGE)
> +  value_range r;
> +  RANGE_QUERY (cfun)->range_of_expr (r, def);
> +  if (r.kind () == VR_RANGE)
>       {
> -      low = wide_int_to_tree (type, minv);
> -      high = wide_int_to_tree (type, maxv);
> +      low = wide_int_to_tree (type, r.lower_bound ());
> +      high = wide_int_to_tree (type, r.upper_bound ());
>       }
>   
>     record_nonwrapping_iv (loop, base, step, stmt, low, high, false, true);
> @@ -4873,7 +4900,6 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
>   {
>     tree type;
>     wide_int minv, maxv, diff, step_wi;
> -  enum value_range_kind rtype;
>   
>     if (TREE_CODE (step) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (var)))
>       return false;
> @@ -4884,8 +4910,9 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
>     if (!def_bb || !dominated_by_p (CDI_DOMINATORS, loop->latch, def_bb))
>       return false;
>   
> -  rtype = get_range_info (var, &minv, &maxv);
> -  if (rtype != VR_RANGE)
> +  value_range r;
> +  RANGE_QUERY (cfun)->range_of_expr (r, var);
> +  if (r.kind () != VR_RANGE)
>       return false;
>   
>     /* VAR is a scev whose evolution part is STEP and value range info
> @@ -4899,11 +4926,11 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
>     type = TREE_TYPE (var);
>     if (tree_int_cst_sign_bit (step))
>       {
> -      diff = minv - wi::to_wide (lower_bound_in_type (type, type));
> +      diff = r.lower_bound () - wi::to_wide (lower_bound_in_type (type, type));
>         step_wi = - step_wi;
>       }
>     else
> -    diff = wi::to_wide (upper_bound_in_type (type, type)) - maxv;
> +    diff = wi::to_wide (upper_bound_in_type (type, type)) - r.upper_bound ();
>   
>     return (wi::geu_p (diff, step_wi));
>   }
> diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
> index 8e8a08bc679..d464c84f164 100644
> --- a/gcc/tree-ssa-phiopt.c
> +++ b/gcc/tree-ssa-phiopt.c
> @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "tree-eh.h"
>   #include "gimple-fold.h"
>   #include "internal-fn.h"
> +#include "gimple-range.h"
>   
>   static unsigned int tree_ssa_phiopt_worker (bool, bool, bool);
>   static bool two_value_replacement (basic_block, basic_block, edge, gphi *,
> @@ -684,7 +685,15 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb,
>       return false;
>   
>     wide_int min, max;
> -  if (get_range_info (lhs, &min, &max) != VR_RANGE)
> +  value_range r;
> +  RANGE_QUERY (cfun)->range_of_expr (r, lhs);
> +
> +  if (r.kind () == VR_RANGE)
> +    {
> +      min = r.lower_bound ();
> +      max = r.upper_bound ();
> +    }
> +  else
>       {
>         int prec = TYPE_PRECISION (TREE_TYPE (lhs));
>         signop sgn = TYPE_SIGN (TREE_TYPE (lhs));
> diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
> index 2d22535af87..870d3cba9ff 100644
> --- a/gcc/tree-ssa-pre.c
> +++ b/gcc/tree-ssa-pre.c
> @@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "tree-ssa-dce.h"
>   #include "tree-cfgcleanup.h"
>   #include "alias.h"
> +#include "gimple-range.h"
>   
>   /* Even though this file is called tree-ssa-pre.c, we actually
>      implement a bit more than just PRE here.  All of them piggy-back
> @@ -3234,16 +3235,18 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
>   	  >= TYPE_PRECISION (TREE_TYPE (expr->u.nary->op[0])))
>         && SSA_NAME_RANGE_INFO (expr->u.nary->op[0]))
>       {
> -      wide_int min, max;
> -      if (get_range_info (expr->u.nary->op[0], &min, &max) == VR_RANGE
> -	  && !wi::neg_p (min, SIGNED)
> -	  && !wi::neg_p (max, SIGNED))
> +      value_range r;
> +      if (RANGE_QUERY (cfun)->range_of_expr (r, expr->u.nary->op[0])
> +	  && r.kind () == VR_RANGE
> +	  && !wi::neg_p (r.lower_bound (), SIGNED)
> +	  && !wi::neg_p (r.upper_bound (), SIGNED))
>   	/* Just handle extension and sign-changes of all-positive ranges.  */
> -	set_range_info (temp,
> -			SSA_NAME_RANGE_TYPE (expr->u.nary->op[0]),
> -			wide_int_storage::from (min, TYPE_PRECISION (type),
> +	set_range_info (temp, VR_RANGE,
> +			wide_int_storage::from (r.lower_bound (),
> +						TYPE_PRECISION (type),
>   						TYPE_SIGN (type)),
> -			wide_int_storage::from (max, TYPE_PRECISION (type),
> +			wide_int_storage::from (r.upper_bound (),
> +						TYPE_PRECISION (type),
>   						TYPE_SIGN (type)));
>       }
>   
> diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
> index 32e1632705b..cc098369e2e 100644
> --- a/gcc/tree-ssa-reassoc.c
> +++ b/gcc/tree-ssa-reassoc.c
> @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "case-cfn-macros.h"
>   #include "tree-ssa-reassoc.h"
>   #include "tree-ssa-math-opts.h"
> +#include "gimple-range.h"
>   
>   /*  This is a simple global reassociation pass.  It is, in part, based
>       on the LLVM pass of the same name (They do some things more/less
> @@ -3221,12 +3222,14 @@ optimize_range_tests_to_bit_test (enum tree_code opcode, int first, int length,
>   	 amount, then we can merge the entry test in the bit test.  In this
>   	 case, if we would need otherwise 2 or more comparisons, then use
>   	 the bit test; in the other cases, the threshold is 3 comparisons.  */
> -      wide_int min, max;
>         bool entry_test_needed;
> +      value_range r;
>         if (TREE_CODE (exp) == SSA_NAME
> -	  && get_range_info (exp, &min, &max) == VR_RANGE
> -	  && wi::leu_p (max - min, prec - 1))
> +	  && RANGE_QUERY (cfun)->range_of_expr (r, exp)
> +	  && r.kind () == VR_RANGE
> +	  && wi::leu_p (r.upper_bound () - r.lower_bound (), prec - 1))
>   	{
> +	  wide_int min = r.lower_bound ();
>   	  wide_int ilowi = wi::to_wide (lowi);
>   	  if (wi::lt_p (min, ilowi, TYPE_SIGN (TREE_TYPE (lowi))))
>   	    {
> diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
> index c7b5e2c6e6b..2f85a609107 100644
> --- a/gcc/tree-ssa-strlen.c
> +++ b/gcc/tree-ssa-strlen.c
> @@ -196,7 +196,7 @@ static void handle_builtin_stxncpy_strncat (bool, gimple_stmt_iterator *);
>   /* Sets MINMAX to either the constant value or the range VAL is in
>      and returns either the constant value or VAL on success or null
>      when the range couldn't be determined.  Uses RVALS when nonnull
> -   to determine the range, otherwise get_range_info.  */
> +   to determine the range, otherwise uses global range info.  */
>   
>   tree
>   get_range (tree val, gimple *stmt, wide_int minmax[2],
> @@ -211,9 +211,9 @@ get_range (tree val, gimple *stmt, wide_int minmax[2],
>     if (TREE_CODE (val) != SSA_NAME)
>       return NULL_TREE;
>   
> +  value_range vr;
>     if (rvals && stmt)
>       {
> -      value_range vr;
>         if (!rvals->range_of_expr (vr, val, stmt))
>   	return NULL_TREE;
>         value_range_kind rng = vr.kind ();
> @@ -225,7 +225,15 @@ get_range (tree val, gimple *stmt, wide_int minmax[2],
>         return val;
>       }
>   
> -  value_range_kind rng = get_range_info (val, minmax, minmax + 1);
> +  // ?? This entire function should use RANGE_QUERY or GLOBAL_RANGE_QUERY,
> +  // instead of doing something different for RVALS and global ranges.
> +
> +  if (!GLOBAL_RANGE_QUERY->range_of_expr (vr, val) || vr.undefined_p ())
> +    return NULL_TREE;
> +
> +  minmax[0] = wi::to_wide (vr.min ());
> +  minmax[1] = wi::to_wide (vr.max ());
> +  value_range_kind rng = vr.kind ();
>     if (rng == VR_RANGE)
>       /* This may be an inverted range whose MINMAX[1] < MINMAX[0].  */
>       return val;
> @@ -929,7 +937,17 @@ dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals)
>   			    rng = VR_UNDEFINED;
>   			}
>   		      else
> -			rng = get_range_info (si->nonzero_chars, &min, &max);
> +			{
> +			  value_range vr;
> +			  GLOBAL_RANGE_QUERY->range_of_expr (vr,
> +							     si->nonzero_chars);
> +			  rng = vr.kind ();
> +			  if (!vr.undefined_p ())
> +			    {
> +			      min = wi::to_wide (vr.min ());
> +			      max = wi::to_wide (vr.max ());
> +			    }
> +			}
>   
>   		      if (rng == VR_RANGE || rng == VR_ANTI_RANGE)
>   			{
> @@ -1809,18 +1827,17 @@ set_strlen_range (tree lhs, wide_int min, wide_int max,
>   	}
>         else if (TREE_CODE (bound) == SSA_NAME)
>   	{
> -	  wide_int minbound, maxbound;
> -	  // FIXME: Use range_query instead of global ranges.
> -	  value_range_kind rng = get_range_info (bound, &minbound, &maxbound);
> -	  if (rng == VR_RANGE)
> +	  value_range r;
> +	  RANGE_QUERY (cfun)->range_of_expr (r, bound);
> +	  if (!r.undefined_p ())
>   	    {
>   	      /* For a bound in a known range, adjust the range determined
>   		 above as necessary.  For a bound in some anti-range or
>   		 in an unknown range, use the range determined by callers.  */
> -	      if (wi::ltu_p (minbound, min))
> -		min = minbound;
> -	      if (wi::ltu_p (maxbound, max))
> -		max = maxbound;
> +	      if (wi::ltu_p (r.lower_bound (), min))
> +		min = r.lower_bound ();
> +	      if (wi::ltu_p (r.upper_bound (), max))
> +		max = r.upper_bound ();
>   	    }
>   	}
>       }
> @@ -2780,12 +2797,15 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt,
>       return false;
>   
>     wide_int cntrange[2];
> +  value_range r;
> +  if (!RANGE_QUERY (cfun)->range_of_expr (r, cnt)
> +      || r.varying_p ()
> +      || r.undefined_p ())
> +    return false;
>   
> -  // FIXME: Use range_query instead of global ranges.
> -  enum value_range_kind rng = get_range_info (cnt, cntrange, cntrange + 1);
> -  if (rng == VR_RANGE)
> -    ;
> -  else if (rng == VR_ANTI_RANGE)
> +  cntrange[0] = wi::to_wide (r.min ());
> +  cntrange[1] = wi::to_wide (r.max ());
> +  if (r.kind () == VR_ANTI_RANGE)
>       {
>         wide_int maxobjsize = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
>   
> @@ -2800,8 +2820,6 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt,
>   	  cntrange[0] = wi::zero (TYPE_PRECISION (TREE_TYPE (cnt)));
>   	}
>       }
> -  else
> -    return false;
>   
>     /* Negative value is the constant string length.  If it's less than
>        the lower bound there is no truncation.  Avoid calling get_stridx()
> @@ -3923,13 +3941,12 @@ get_len_or_size (gimple *stmt, tree arg, int idx,
>   	}
>         else if (TREE_CODE (si->nonzero_chars) == SSA_NAME)
>   	{
> -	  wide_int min, max;
> -	  // FIXME: Use range_query instead of global ranges.
> -	  value_range_kind rng = get_range_info (si->nonzero_chars, &min, &max);
> -	  if (rng == VR_RANGE)
> +	  value_range r;
> +	  RANGE_QUERY (cfun)->range_of_expr (r, si->nonzero_chars);
> +	  if (r.kind () == VR_RANGE)
>   	    {
> -	      lenrng[0] = min.to_uhwi ();
> -	      lenrng[1] = max.to_uhwi ();
> +	      lenrng[0] = r.lower_bound ().to_uhwi ();
> +	      lenrng[1] = r.upper_bound ().to_uhwi ();
>   	      *nulterm = si->full_string_p;
>   	    }
>   	}
> @@ -5301,17 +5318,13 @@ handle_integral_assign (gimple_stmt_iterator *gsi, bool *cleanup_eh,
>   		  /* Reading a character before the final '\0'
>   		     character.  Just set the value range to ~[0, 0]
>   		     if we don't have anything better.  */
> -		  wide_int min, max;
> -		  signop sign = TYPE_SIGN (lhs_type);
> -		  int prec = TYPE_PRECISION (lhs_type);
> -		  // FIXME: Use range_query instead of global ranges.
> -		  value_range_kind vr = get_range_info (lhs, &min, &max);
> -		  if (vr == VR_VARYING
> -		      || (vr == VR_RANGE
> -			  && min == wi::min_value (prec, sign)
> -			  && max == wi::max_value (prec, sign)))
> -		    set_range_info (lhs, VR_ANTI_RANGE,
> -				    wi::zero (prec), wi::zero (prec));
> +		  value_range r;
> +		  if (!RANGE_QUERY (cfun)->range_of_expr (r, lhs)
> +		      || r.varying_p ())
> +		    {
> +		      r.set_nonzero (lhs_type);
> +		      set_range_info (lhs, r);
> +		    }
>   		}
>   	    }
>   	}
> diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
> index a0238710e72..514cec1d927 100644
> --- a/gcc/tree-ssa-structalias.c
> +++ b/gcc/tree-ssa-structalias.c
> @@ -43,6 +43,7 @@
>   #include "attribs.h"
>   #include "tree-ssa.h"
>   #include "tree-cfg.h"
> +#include "gimple-range.h"
>   
>   /* The idea behind this analyzer is to generate set constraints from the
>      program, then solve the resulting constraints in order to generate the
> @@ -6740,7 +6741,9 @@ find_what_p_points_to (tree fndecl, tree p)
>     struct ptr_info_def *pi;
>     tree lookup_p = p;
>     varinfo_t vi;
> -  bool nonnull = get_ptr_nonnull (p);
> +  value_range vr;
> +  GLOBAL_RANGE_QUERY->range_of_expr (vr, p);
> +  bool nonnull = vr.nonzero_p ();
>   
>     /* For parameters, get at the points-to set for the actual parm
>        decl.  */
> @@ -6758,8 +6761,7 @@ find_what_p_points_to (tree fndecl, tree p)
>     pi->pt = find_what_var_points_to (fndecl, vi);
>     /* Conservatively set to NULL from PTA (to true). */
>     pi->pt.null = 1;
> -  /* Preserve pointer nonnull computed by VRP.  See get_ptr_nonnull
> -     in gcc/tree-ssaname.c for more information.  */
> +  /* Preserve pointer nonnull globally computed.  */
>     if (nonnull)
>       set_ptr_nonnull (p);
>   }
> diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
> index f55ce1939ac..b352f68b1b7 100644
> --- a/gcc/tree-ssa-uninit.c
> +++ b/gcc/tree-ssa-uninit.c
> @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "attribs.h"
>   #include "builtins.h"
>   #include "calls.h"
> +#include "gimple-range.h"
>   
>   /* This implements the pass that does predicate aware warning on uses of
>      possibly uninitialized variables.  The pass first collects the set of
> @@ -1606,11 +1607,14 @@ find_var_cmp_const (pred_chain_union preds, gphi *phi, gimple **flag_def,
>   	       flag_var <= [min, max] ->  flag_var < [min, max+1]
>   	       flag_var >= [min, max] ->  flag_var > [min-1, max]
>   	     if no overflow/wrap.  */
> -	  wide_int min, max;
>   	  tree type = TREE_TYPE (cond_lhs);
> +	  value_range r;
>   	  if (!INTEGRAL_TYPE_P (type)
> -	      || get_range_info (cond_rhs, &min, &max) != VR_RANGE)
> +	      || !RANGE_QUERY (cfun)->range_of_expr (r, cond_rhs)
> +	      || r.kind () != VR_RANGE)
>   	    continue;
> +	  wide_int min = r.lower_bound ();
> +	  wide_int max = r.upper_bound ();
>   	  if (code == LE_EXPR
>   	      && max != wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)))
>   	    {
> diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
> index 7f65c4ce839..225d831003f 100644
> --- a/gcc/tree-switch-conversion.c
> +++ b/gcc/tree-switch-conversion.c
> @@ -50,6 +50,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
>   #include "target.h"
>   #include "tree-into-ssa.h"
>   #include "omp-general.h"
> +#include "gimple-range.h"
>   
>   /* ??? For lang_hooks.types.type_for_mode, but is there a word_mode
>      type in the GIMPLE type system that is language-independent?  */
> @@ -1553,12 +1554,15 @@ bit_test_cluster::emit (tree index_expr, tree index_type,
>   
>     /* If every possible relative value of the index expression is a valid shift
>        amount, then we can merge the entry test in the bit test.  */
> -  wide_int min, max;
>     bool entry_test_needed;
> +  value_range r;
>     if (TREE_CODE (index_expr) == SSA_NAME
> -      && get_range_info (index_expr, &min, &max) == VR_RANGE
> -      && wi::leu_p (max - min, prec - 1))
> +      && RANGE_QUERY (cfun)->range_of_expr (r, index_expr)
> +      && r.kind () == VR_RANGE
> +      && wi::leu_p (r.upper_bound () - r.lower_bound (), prec - 1))
>       {
> +      wide_int min = r.lower_bound ();
> +      wide_int max = r.upper_bound ();
>         tree index_type = TREE_TYPE (index_expr);
>         minval = fold_convert (index_type, minval);
>         wide_int iminval = wi::to_wide (minval);
> diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
> index 803de3fc287..99be2314029 100644
> --- a/gcc/tree-vect-patterns.c
> +++ b/gcc/tree-vect-patterns.c
> @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "predict.h"
>   #include "tree-vector-builder.h"
>   #include "vec-perm-indices.h"
> +#include "gimple-range.h"
>   
>   /* Return true if we have a useful VR_RANGE range for VAR, storing it
>      in *MIN_VALUE and *MAX_VALUE if so.  Note the range in the dump files.  */
> @@ -55,7 +56,13 @@ along with GCC; see the file COPYING3.  If not see
>   static bool
>   vect_get_range_info (tree var, wide_int *min_value, wide_int *max_value)
>   {
> -  value_range_kind vr_type = get_range_info (var, min_value, max_value);
> +  value_range vr;
> +  RANGE_QUERY (cfun)->range_of_expr (vr, var);
> +  if (vr.undefined_p ())
> +    vr.set_varying (TREE_TYPE (var));
> +  *min_value = wi::to_wide (vr.min ());
> +  *max_value = wi::to_wide (vr.max ());
> +  value_range_kind vr_type = vr.kind ();
>     wide_int nonzero = get_nonzero_bits (var);
>     signop sgn = TYPE_SIGN (TREE_TYPE (var));
>     if (intersect_range_with_nonzero_bits (vr_type, min_value, max_value,
> @@ -3437,13 +3444,14 @@ vect_recog_divmod_pattern (vec_info *vinfo,
>         else
>   	t3 = t2;
>   
> -      wide_int oprnd0_min, oprnd0_max;
>         int msb = 1;
> -      if (get_range_info (oprnd0, &oprnd0_min, &oprnd0_max) == VR_RANGE)
> +      value_range r;
> +      RANGE_QUERY (cfun)->range_of_expr (r, oprnd0);
> +      if (r.kind () == VR_RANGE)
>   	{
> -	  if (!wi::neg_p (oprnd0_min, TYPE_SIGN (itype)))
> +	  if (!wi::neg_p (r.lower_bound (), TYPE_SIGN (itype)))
>   	    msb = 0;
> -	  else if (wi::neg_p (oprnd0_max, TYPE_SIGN (itype)))
> +	  else if (wi::neg_p (r.upper_bound (), TYPE_SIGN (itype)))
>   	    msb = -1;
>   	}
>   
> diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
> index b0f1c47f05c..6a723efc0d8 100644
> --- a/gcc/tree-vrp.c
> +++ b/gcc/tree-vrp.c
> @@ -228,7 +228,7 @@ intersect_range_with_nonzero_bits (enum value_range_kind vr_type,
>   	  vr_type = VR_RANGE;
>   	}
>       }
> -  if (vr_type == VR_RANGE)
> +  if (vr_type == VR_RANGE || vr_type == VR_VARYING)
>       {
>         *max = wi::round_down_for_mask (*max, nonzero_bits);
>   
> @@ -1717,7 +1717,7 @@ register_edge_assert_for_2 (tree name, edge e,
>            simply register the same assert for it.  */
>         if (CONVERT_EXPR_CODE_P (rhs_code))
>   	{
> -	  wide_int rmin, rmax;
> +	  value_range vr;
>   	  tree rhs1 = gimple_assign_rhs1 (def_stmt);
>   	  if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
>   	      && TREE_CODE (rhs1) == SSA_NAME
> @@ -1739,13 +1739,14 @@ register_edge_assert_for_2 (tree name, edge e,
>   	      && int_fits_type_p (val, TREE_TYPE (rhs1))
>   	      && ((TYPE_PRECISION (TREE_TYPE (name))
>   		   > TYPE_PRECISION (TREE_TYPE (rhs1)))
> -		  || (get_range_info (rhs1, &rmin, &rmax) == VR_RANGE
> +		  || ((RANGE_QUERY (cfun)->range_of_expr (vr, rhs1)
> +		       && vr.kind () == VR_RANGE)
>   		      && wi::fits_to_tree_p
> -			   (widest_int::from (rmin,
> +			   (widest_int::from (vr.lower_bound (),
>   					      TYPE_SIGN (TREE_TYPE (rhs1))),
>   			    TREE_TYPE (name))
>   		      && wi::fits_to_tree_p
> -			   (widest_int::from (rmax,
> +			   (widest_int::from (vr.upper_bound (),
>   					      TYPE_SIGN (TREE_TYPE (rhs1))),
>   			    TREE_TYPE (name)))))
>   	    add_assert_info (asserts, rhs1, rhs1,
> @@ -4631,16 +4632,14 @@ determine_value_range_1 (value_range *vr, tree expr)
>       vr->set (expr);
>     else
>       {
> -      value_range_kind kind;
> -      wide_int min, max;
> +      value_range r;
>         /* For SSA names try to extract range info computed by VRP.  Otherwise
>   	 fall back to varying.  */
>         if (TREE_CODE (expr) == SSA_NAME
>   	  && INTEGRAL_TYPE_P (TREE_TYPE (expr))
> -	  && (kind = get_range_info (expr, &min, &max)) != VR_VARYING)
> -	vr->set (wide_int_to_tree (TREE_TYPE (expr), min),
> -		 wide_int_to_tree (TREE_TYPE (expr), max),
> -		 kind);
> +	  && RANGE_QUERY (cfun)->range_of_expr (r, expr)
> +	  && !r.undefined_p ())
> +	*vr = r;
>         else
>   	vr->set_varying (TREE_TYPE (expr));
>       }
> diff --git a/gcc/tree.c b/gcc/tree.c
> index 31ac4245c9c..3d5111628b5 100644
> --- a/gcc/tree.c
> +++ b/gcc/tree.c
> @@ -68,6 +68,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "tree-vector-builder.h"
>   #include "gimple-fold.h"
>   #include "escaped_string.h"
> +#include "gimple-range.h"
>   
>   /* Tree code classes.  */
>   
> @@ -13834,8 +13835,8 @@ get_range_pos_neg (tree arg)
>   
>     if (TREE_CODE (arg) != SSA_NAME)
>       return 3;
> -  wide_int arg_min, arg_max;
> -  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
> +  value_range r;
> +  while (!GLOBAL_RANGE_QUERY->range_of_expr (r, arg) || r.kind () != VR_RANGE)
>       {
>         gimple *g = SSA_NAME_DEF_STMT (arg);
>         if (is_gimple_assign (g)
> @@ -13861,16 +13862,16 @@ get_range_pos_neg (tree arg)
>       {
>         /* For unsigned values, the "positive" range comes
>   	 below the "negative" range.  */
> -      if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED))
> +      if (!wi::neg_p (wi::sext (r.upper_bound (), prec), SIGNED))
>   	return 1;
> -      if (wi::neg_p (wi::sext (arg_min, prec), SIGNED))
> +      if (wi::neg_p (wi::sext (r.lower_bound (), prec), SIGNED))
>   	return 2;
>       }
>     else
>       {
> -      if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED))
> +      if (!wi::neg_p (wi::sext (r.lower_bound (), prec), SIGNED))
>   	return 1;
> -      if (wi::neg_p (wi::sext (arg_max, prec), SIGNED))
> +      if (wi::neg_p (wi::sext (r.upper_bound (), prec), SIGNED))
>   	return 2;
>       }
>     return 3;
> diff --git a/gcc/vr-values.c b/gcc/vr-values.c
> index a89f0b646ae..02acb46cb20 100644
> --- a/gcc/vr-values.c
> +++ b/gcc/vr-values.c
> @@ -117,14 +117,16 @@ vr_values::get_lattice_entry (const_tree var)
>   	     default definitions of PARM_DECLs.  */
>   	  if (POINTER_TYPE_P (TREE_TYPE (sym))
>   	      && (nonnull_arg_p (sym)
> -		  || get_ptr_nonnull (var)))
> +		  || (GLOBAL_RANGE_QUERY->range_of_expr (*vr,
> +						const_cast <tree> (var))
> +		      && vr->nonzero_p ())))
>   	    {
>   	      vr->set_nonzero (TREE_TYPE (sym));
>   	      vr->equiv_clear ();
>   	    }
>   	  else if (INTEGRAL_TYPE_P (TREE_TYPE (sym)))
>   	    {
> -	      get_range_info (var, *vr);
> +	      GLOBAL_RANGE_QUERY->range_of_expr (*vr, const_cast <tree> (var));
>   	      if (vr->undefined_p ())
>   		vr->set_varying (TREE_TYPE (sym));
>   	    }
> @@ -262,7 +264,7 @@ vr_values::update_value_range (const_tree var, value_range_equiv *new_vr)
>     if (INTEGRAL_TYPE_P (TREE_TYPE (var)))
>       {
>         value_range_equiv nr;
> -      get_range_info (var, nr);
> +      GLOBAL_RANGE_QUERY->range_of_expr (nr, const_cast <tree> (var));
>         if (!nr.undefined_p ())
>   	new_vr->intersect (&nr);
>       }
> @@ -3829,13 +3831,13 @@ simplify_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
>         || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop))
>       return false;
>   
> -  /* Get the value-range of the inner operand.  Use get_range_info in
> +  /* Get the value-range of the inner operand.  Use global ranges in
>        case innerop was created during substitute-and-fold.  */
>     wide_int imin, imax;
>     value_range vr;
>     if (!INTEGRAL_TYPE_P (TREE_TYPE (innerop)))
>       return false;
> -  get_range_info (innerop, vr);
> +  RANGE_QUERY (cfun)->range_of_expr (vr, innerop, stmt);
>     if (vr.undefined_p () || vr.varying_p ())
>       return false;
>     innermin = widest_int::from (vr.lower_bound (), TYPE_SIGN (TREE_TYPE (innerop)));
> 


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] Common API for accessing global and on-demand ranges.
  2021-05-24 19:13 ` Martin Sebor
@ 2021-05-25  7:06   ` Aldy Hernandez
  0 siblings, 0 replies; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-25  7:06 UTC (permalink / raw)
  To: Martin Sebor, GCC patches, Andrew MacLeod; +Cc: Martin Sebor



On 5/24/21 9:13 PM, Martin Sebor wrote:
> On 5/21/21 5:39 AM, Aldy Hernandez via Gcc-patches wrote:

>> +  /* 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;
>> +
> 
> Mostly out of curiosity: why the 'x_' prefix?  (I'm used to seeing
> that in the expansion of the option macros but it seems out of place
> here.)

To disambiguate from the similarly named type.  I thought of using 
"query" for the field name, but that seemed too generic as to be confusing.

> 
>>     /* Last statement uid.  */
>>     int last_stmt_uid;
>> @@ -712,4 +718,14 @@ extern const char *current_function_name (void);
>>   extern void used_types_insert (tree);
>> +extern range_query *get_global_range_query ();
>> +
>> +// Returns the currently active range access class.  This is meant to 
>> be used
>> +// with the `class range_query' API.  When there is no active range 
>> class,
>> +// global ranges are used.
>> +#define RANGE_QUERY(fun) (fun)->x_range_query
>> +
>> +// As above, but for accessing global ranges between passes.
>> +#define GLOBAL_RANGE_QUERY get_global_range_query ()
> 
> Unless there's some reason that escapes me, could these be functions
> (possibly defined inline) rather than macros?  (They're a lot easier
> to work with, such as when I want to trace calls in some way.)

Sure, we could make it an inline function.

> 
>> +
>>   #endif  /* GCC_FUNCTION_H */
>> diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
>> index 2c922e32913..c645d15f5af 100644
>> --- a/gcc/gimple-range-cache.cc
>> +++ b/gcc/gimple-range-cache.cc
>> @@ -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;
>>   }
>> diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
>> index 710bc7f9632..4e1aeee8ed0 100644
>> --- a/gcc/gimple-range.cc
>> +++ b/gcc/gimple-range.cc
>> @@ -1402,3 +1402,133 @@ 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.
> 
> I realize this is just being moved from elsewhere but I would suggest
> to take this opportunity and also document the effects on the range
> argument.
> 
>> +
>> +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. 
> 
> I couldn't help but notice another variation on the dubious ???
> yet wide-spread convention:
>    https://gcc.gnu.org/pipermail/gcc-patches/2021-May/570442.html

Per the comment in that message, my use indicates something that could 
be done different but is not a bug.

> 
>> 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;
>> +
>> +range_query *
>> +get_global_range_query ()
>> +{
>> +  if (cfun)
>> +    return RANGE_QUERY (cfun);
>> +
>> +  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;
>> +}
>> +
>> +void
>> +enable_ranger ()
>> +{
>> +  gimple_ranger *r;
>> +
>> +  if (param_evrp_mode & EVRP_MODE_TRACE)
>> +    r = new trace_ranger;
>> +  else
>> +    r = new gimple_ranger;
>> +
>> +  RANGE_QUERY (cfun) = r;
>> +}
>> +
>> +void
>> +disable_ranger (bool export_ranges)
>> +{
>> +  gimple_ranger *r = (gimple_ranger *) RANGE_QUERY (cfun);
>> +
>> +  if (export_ranges)
>> +    r->export_global_ranges ();
>> +
>> +  delete r;
> 
> The above is a downcast from range_query*, so if the instance is
> something else the code won't work correctly and might crash,
> right?  Or it might call the wrong function/dtor.  Should there
> be a check of some sort to make sure that doesn't happen?

Yeah, Andrew and I had argued about this.  The use is confined to two 
tiny functions that can be seen in one screenful 
(enable/disable_ranger), and no one should be setting x_range_query 
directly.

Aldy


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun).
  2021-05-21 11:39 ` [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun) Aldy Hernandez
@ 2021-05-25  8:43   ` Richard Biener
  2021-05-25 16:17   ` Aldy Hernandez
  1 sibling, 0 replies; 31+ messages in thread
From: Richard Biener @ 2021-05-25  8:43 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: GCC patches, Andrew MacLeod, Martin Sebor

On Fri, May 21, 2021 at 2:34 PM Aldy Hernandez via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> This patch converts the Walloca pass to use an on-demand ranger
> accesible with RANGE_QUERY instead of having to create a ranger and pass
> it around.
>
> Tested on x86-64 Linux.
>
> OK?
>
> gcc/ChangeLog:
>
>         * gimple-ssa-warn-alloca.c (alloca_call_type): Use RANGE_QUERY
>         instead of query argument.
>         (pass_walloca::execute): Enable and disable global ranger.
> ---
>  gcc/gimple-ssa-warn-alloca.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
> index e9a24d4d1d0..12f4bce3be8 100644
> --- a/gcc/gimple-ssa-warn-alloca.c
> +++ b/gcc/gimple-ssa-warn-alloca.c
> @@ -165,7 +165,7 @@ adjusted_warn_limit (bool idx)
>  // call was created by the gimplifier for a VLA.
>
>  static class alloca_type_and_limit
> -alloca_call_type (range_query &query, gimple *stmt, bool is_vla)
> +alloca_call_type (gimple *stmt, bool is_vla)
>  {
>    gcc_assert (gimple_alloca_call_p (stmt));
>    tree len = gimple_call_arg (stmt, 0);
> @@ -217,7 +217,7 @@ alloca_call_type (range_query &query, gimple *stmt, bool is_vla)
>    int_range_max r;
>    if (warn_limit_specified_p (is_vla)
>        && TREE_CODE (len) == SSA_NAME
> -      && query.range_of_expr (r, len, stmt)
> +      && RANGE_QUERY (cfun)->range_of_expr (r, len, stmt)

please avoid new references to 'cfun' and instead pass ...

>        && !r.varying_p ())
>      {
>        // The invalid bits are anything outside of [0, MAX_SIZE].
> @@ -256,7 +256,7 @@ in_loop_p (gimple *stmt)
>  unsigned int
>  pass_walloca::execute (function *fun)

... 'fun' down.

>  {
> -  gimple_ranger ranger;
> +  enable_ranger ();
>    basic_block bb;
>    FOR_EACH_BB_FN (bb, fun)
>      {
> @@ -290,7 +290,7 @@ pass_walloca::execute (function *fun)
>             continue;
>
>           class alloca_type_and_limit t
> -           = alloca_call_type (ranger, stmt, is_vla);
> +           = alloca_call_type (stmt, is_vla);
>
>           unsigned HOST_WIDE_INT adjusted_alloca_limit
>             = adjusted_warn_limit (false);
> @@ -383,6 +383,7 @@ pass_walloca::execute (function *fun)
>             }
>         }
>      }
> +  disable_ranger ();
>    return 0;
>  }
>
> --
> 2.31.1
>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 4/5] Convert remaining passes to RANGE_QUERY.
  2021-05-24 19:34   ` Martin Sebor
@ 2021-05-25  8:47     ` Richard Biener
  2021-05-25  9:15       ` Aldy Hernandez
  2021-05-25 11:26       ` Aldy Hernandez
  2021-05-25  8:48     ` Aldy Hernandez
  1 sibling, 2 replies; 31+ messages in thread
From: Richard Biener @ 2021-05-25  8:47 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Aldy Hernandez, GCC patches, Andrew MacLeod, Martin Sebor

On Mon, May 24, 2021 at 10:02 PM Martin Sebor via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> On 5/21/21 5:39 AM, Aldy Hernandez via Gcc-patches wrote:
> > This patch converts the remaining users of get_range_info and
> > get_ptr_nonnull to the range_query API.
> >
> > No effort was made to move passes away from VR_ANTI_RANGE, or any other
> > use of deprecated methods.  This was a straight up conversion to the new
> > API, nothing else.
>
> A question about the uses of the RANGE_QUERY() and GLOBAL_RANGE_QUERY()
> macros (hopefully functions): some clients in this patch call one or
> the other based on whether cfun is set or null, while others call it
> without such testing.  That suggests that the former clients might
> be making the assumption that cfun is null while the latter ones
> make the opposite assumption that cfun is not null.  It seems that
> the code would be safer/more future-proof if it avoided making
> these assumptions.
>
> That could be done by introducing a function like this one:
>
>    range_query&
>    get_range_query (const function *func = cfun)
>    {
>      if (func)
>        return func->x_range_query;
>      return *get_global_range_query ();
>    }
>
> This function would be easier to use since clients wouldn't have
> to worry about when cfun is null.

Note that IPA passes also work on specific 'fun', not 'cfun' and
that 'cfun' stands in the way of threading GCC.  So please avoid
adding new references, even more so default args.

I wonder if SSA_NAME_RANGE_INFO is then obsolete?  What if
"ranger" is not enabled/available - will this effectively regress things
by not exposing SSA_NAME_RANGE_INFO (which also encodes
nonzero bits & friends)?

Richard.

>
> Since all clients assume the result is nonnull the function returns
> a reference rather a pointer.  (That's presumably also true for
> get_global_range_query()).
>
> Martin
>
> >
> > Tested on x86-64 Linux.
> >
> > OK?
> >
> > gcc/ChangeLog:
> >
> >       * builtins.c (check_nul_terminated_array): Convert to RANGE_QUERY.
> >       (expand_builtin_strnlen): Same.
> >       (determine_block_size): Same.
> >       * fold-const.c (expr_not_equal_to): Same.
> >       * gimple-fold.c (size_must_be_zero_p): Same.
> >       * gimple-match-head.c: Include gimple-range.h.
> >       * gimple-pretty-print.c (dump_ssaname_info): Convert to RANGE_QUERY.
> >       * gimple-ssa-warn-restrict.c
> >       (builtin_memref::extend_offset_range): Same.
> >       * graphite-sese-to-poly.c (add_param_constraints): Same.
> >       * internal-fn.c (get_min_precision): Same.
> >       * ipa-fnsummary.c (set_switch_stmt_execution_predicate): Same.
> >       * ipa-prop.c (ipa_compute_jump_functions_for_edge): Same.
> >       * match.pd: Same.
> >       * tree-data-ref.c (split_constant_offset): Same.
> >       (dr_step_indicator): Same.
> >       * tree-dfa.c (get_ref_base_and_extent): Same.
> >       * tree-scalar-evolution.c (iv_can_overflow_p): Same.
> >       * tree-ssa-loop-niter.c (refine_value_range_using_guard): Same.
> >       (determine_value_range): Same.
> >       (record_nonwrapping_iv): Same.
> >       (infer_loop_bounds_from_signedness): Same.
> >       (scev_var_range_cant_overflow): Same.
> >       * tree-ssa-phiopt.c (two_value_replacement): Same.
> >       * tree-ssa-pre.c (insert_into_preds_of_block): Same.
> >       * tree-ssa-reassoc.c (optimize_range_tests_to_bit_test): Same.
> >       * tree-ssa-strlen.c (handle_builtin_stxncpy_strncat): Same.
> >       (get_range): Same.
> >       (dump_strlen_info): Same.
> >       (set_strlen_range): Same.
> >       (maybe_diag_stxncpy_trunc): Same.
> >       (get_len_or_size): Same.
> >       (handle_integral_assign): Same.
> >       * tree-ssa-structalias.c (find_what_p_points_to): Same.
> >       * tree-ssa-uninit.c (find_var_cmp_const): Same.
> >       * tree-switch-conversion.c (bit_test_cluster::emit): Same.
> >       * tree-vect-patterns.c (vect_get_range_info): Same.
> >       (vect_recog_divmod_pattern): Same.
> >       * tree-vrp.c (intersect_range_with_nonzero_bits): Same.
> >       (register_edge_assert_for_2): Same.
> >       (determine_value_range_1): Same.
> >       * tree.c (get_range_pos_neg): Same.
> >       * vr-values.c (vr_values::get_lattice_entry): Same.
> >       (vr_values::update_value_range): Same.
> >       (simplify_conversion_using_ranges): Same.
> > ---
> >   gcc/builtins.c                 | 40 ++++++++++------
> >   gcc/fold-const.c               |  8 +++-
> >   gcc/gimple-fold.c              |  7 ++-
> >   gcc/gimple-match-head.c        |  1 +
> >   gcc/gimple-pretty-print.c      | 12 ++++-
> >   gcc/gimple-ssa-warn-restrict.c |  8 +++-
> >   gcc/graphite-sese-to-poly.c    |  9 +++-
> >   gcc/internal-fn.c              | 14 +++---
> >   gcc/ipa-fnsummary.c            | 11 ++++-
> >   gcc/ipa-prop.c                 | 16 +++----
> >   gcc/match.pd                   | 19 ++++++--
> >   gcc/tree-data-ref.c            | 24 ++++++++--
> >   gcc/tree-dfa.c                 | 14 +++++-
> >   gcc/tree-scalar-evolution.c    | 13 +++++-
> >   gcc/tree-ssa-loop-niter.c      | 81 +++++++++++++++++++++-----------
> >   gcc/tree-ssa-phiopt.c          | 11 ++++-
> >   gcc/tree-ssa-pre.c             | 19 ++++----
> >   gcc/tree-ssa-reassoc.c         |  9 ++--
> >   gcc/tree-ssa-strlen.c          | 85 ++++++++++++++++++++--------------
> >   gcc/tree-ssa-structalias.c     |  8 ++--
> >   gcc/tree-ssa-uninit.c          |  8 +++-
> >   gcc/tree-switch-conversion.c   | 10 ++--
> >   gcc/tree-vect-patterns.c       | 18 +++++--
> >   gcc/tree-vrp.c                 | 21 ++++-----
> >   gcc/tree.c                     | 13 +++---
> >   gcc/vr-values.c                | 12 +++--
> >   26 files changed, 332 insertions(+), 159 deletions(-)
> >
> > diff --git a/gcc/builtins.c b/gcc/builtins.c
> > index e1b284846b1..deb7c083315 100644
> > --- a/gcc/builtins.c
> > +++ b/gcc/builtins.c
> > @@ -79,6 +79,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "tree-outof-ssa.h"
> >   #include "attr-fnspec.h"
> >   #include "demangle.h"
> > +#include "gimple-range.h"
> >
> >   struct target_builtins default_target_builtins;
> >   #if SWITCHABLE_TARGET
> > @@ -1214,14 +1215,15 @@ check_nul_terminated_array (tree expr, tree src,
> >     wide_int bndrng[2];
> >     if (bound)
> >       {
> > -      if (TREE_CODE (bound) == INTEGER_CST)
> > -     bndrng[0] = bndrng[1] = wi::to_wide (bound);
> > -      else
> > -     {
> > -       value_range_kind rng = get_range_info (bound, bndrng, bndrng + 1);
> > -       if (rng != VR_RANGE)
> > -         return true;
> > -     }
> > +      value_range r;
> > +
> > +      GLOBAL_RANGE_QUERY->range_of_expr (r, bound);
> > +
> > +      if (r.kind () != VR_RANGE)
> > +     return true;
> > +
> > +      bndrng[0] = r.lower_bound ();
> > +      bndrng[1] = r.upper_bound ();
> >
> >         if (exact)
> >       {
> > @@ -3827,9 +3829,12 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
> >       return NULL_RTX;
> >
> >     wide_int min, max;
> > -  enum value_range_kind rng = get_range_info (bound, &min, &max);
> > -  if (rng != VR_RANGE)
> > +  value_range r;
> > +  GLOBAL_RANGE_QUERY->range_of_expr (r, bound);
> > +  if (r.kind () != VR_RANGE)
> >       return NULL_RTX;
> > +  min = r.lower_bound ();
> > +  max = r.upper_bound ();
> >
> >     if (!len || TREE_CODE (len) != INTEGER_CST)
> >       {
> > @@ -3897,7 +3902,16 @@ determine_block_size (tree len, rtx len_rtx,
> >       *probable_max_size = *max_size = GET_MODE_MASK (GET_MODE (len_rtx));
> >
> >         if (TREE_CODE (len) == SSA_NAME)
> > -     range_type = get_range_info (len, &min, &max);
> > +     {
> > +       value_range r;
> > +       GLOBAL_RANGE_QUERY->range_of_expr (r, len);
> > +       range_type = r.kind ();
> > +       if (range_type != VR_UNDEFINED)
> > +         {
> > +           min = wi::to_wide (r.min ());
> > +           max = wi::to_wide (r.max ());
> > +         }
> > +     }
> >         if (range_type == VR_RANGE)
> >       {
> >         if (wi::fits_uhwi_p (min) && *min_size < min.to_uhwi ())
> > @@ -4914,8 +4928,8 @@ check_read_access (tree exp, tree src, tree bound /* = NULL_TREE */,
> >   /* If STMT is a call to an allocation function, returns the constant
> >      maximum size of the object allocated by the call represented as
> >      sizetype.  If nonnull, sets RNG1[] to the range of the size.
> > -   When nonnull, uses RVALS for range information, otherwise calls
> > -   get_range_info to get it.
> > +   When nonnull, uses RVALS for range information, otherwise gets global
> > +   range info.
> >      Returns null when STMT is not a call to a valid allocation function.  */
> >
> >   tree
> > diff --git a/gcc/fold-const.c b/gcc/fold-const.c
> > index 5a41524702b..d680ba1442f 100644
> > --- a/gcc/fold-const.c
> > +++ b/gcc/fold-const.c
> > @@ -83,6 +83,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "tree-vector-builder.h"
> >   #include "vec-perm-indices.h"
> >   #include "asan.h"
> > +#include "gimple-range.h"
> >
> >   /* Nonzero if we are folding constants inside an initializer; zero
> >      otherwise.  */
> > @@ -10686,7 +10687,12 @@ expr_not_equal_to (tree t, const wide_int &w)
> >       case SSA_NAME:
> >         if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
> >       return false;
> > -      get_range_info (t, vr);
> > +
> > +      if (cfun)
> > +     RANGE_QUERY (cfun)->range_of_expr (vr, t);
> > +      else
> > +     GLOBAL_RANGE_QUERY->range_of_expr (vr, t);
> > +
> >         if (!vr.undefined_p ()
> >         && !vr.contains_p (wide_int_to_tree (TREE_TYPE (t), w)))
> >       return true;
> > diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
> > index 68717cf1542..228fa1b357f 100644
> > --- a/gcc/gimple-fold.c
> > +++ b/gcc/gimple-fold.c
> > @@ -873,7 +873,12 @@ size_must_be_zero_p (tree size)
> >     value_range valid_range (build_int_cst (type, 0),
> >                          wide_int_to_tree (type, ssize_max));
> >     value_range vr;
> > -  get_range_info (size, vr);
> > +  if (cfun)
> > +    RANGE_QUERY (cfun)->range_of_expr (vr, size);
> > +  else
> > +    GLOBAL_RANGE_QUERY->range_of_expr (vr, size);
> > +  if (vr.undefined_p ())
> > +    vr.set_varying (TREE_TYPE (size));
> >     vr.intersect (&valid_range);
> >     return vr.zero_p ();
> >   }
> > diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c
> > index b084a31572a..7112c116835 100644
> > --- a/gcc/gimple-match-head.c
> > +++ b/gcc/gimple-match-head.c
> > @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "tree-eh.h"
> >   #include "dbgcnt.h"
> >   #include "tm.h"
> > +#include "gimple-range.h"
> >
> >   /* Forward declarations of the private auto-generated matchers.
> >      They expect valueized operands in canonical order and do not
> > diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
> > index 0ef01e6420b..62d895d1625 100644
> > --- a/gcc/gimple-pretty-print.c
> > +++ b/gcc/gimple-pretty-print.c
> > @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "attribs.h"
> >   #include "asan.h"
> >   #include "cfgloop.h"
> > +#include "gimple-range.h"
> >
> >   /* Disable warnings about quoting issues in the pp_xxx calls below
> >      that (intentionally) don't follow GCC diagnostic conventions.  */
> > @@ -2263,8 +2264,17 @@ dump_ssaname_info (pretty_printer *buffer, tree node, int spc)
> >         && SSA_NAME_RANGE_INFO (node))
> >       {
> >         wide_int min, max, nonzero_bits;
> > -      value_range_kind range_type = get_range_info (node, &min, &max);
> > +      value_range r;
> >
> > +      GLOBAL_RANGE_QUERY->range_of_expr (r, node);
> > +      value_range_kind range_type = r.kind ();
> > +      if (!r.undefined_p ())
> > +     {
> > +       min = wi::to_wide (r.min ());
> > +       max = wi::to_wide (r.max ());
> > +     }
> > +
> > +      // FIXME: Use irange::dump() instead.
> >         if (range_type == VR_VARYING)
> >       pp_printf (buffer, "# RANGE VR_VARYING");
> >         else if (range_type == VR_RANGE || range_type == VR_ANTI_RANGE)
> > diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
> > index ad37f20afaa..a59731c2bc2 100644
> > --- a/gcc/gimple-ssa-warn-restrict.c
> > +++ b/gcc/gimple-ssa-warn-restrict.c
> > @@ -349,7 +349,13 @@ builtin_memref::extend_offset_range (tree offset)
> >         /* There is a global version here because
> >            check_bounds_or_overlap may be called from gimple
> >            fold during gimple lowering.  */
> > -       rng = get_range_info (offset, &min, &max);
> > +       RANGE_QUERY (cfun)->range_of_expr (vr, offset, stmt);
> > +       rng = vr.kind ();
> > +       if (!vr.undefined_p ())
> > +         {
> > +           min = wi::to_wide (vr.min ());
> > +           max = wi::to_wide (vr.max ());
> > +         }
> >       }
> >         if (rng == VR_ANTI_RANGE && wi::lts_p (max, min))
> >       {
> > diff --git a/gcc/graphite-sese-to-poly.c b/gcc/graphite-sese-to-poly.c
> > index eebf2e02cfc..2d332f69a92 100644
> > --- a/gcc/graphite-sese-to-poly.c
> > +++ b/gcc/graphite-sese-to-poly.c
> > @@ -418,13 +418,18 @@ static void
> >   add_param_constraints (scop_p scop, graphite_dim_t p, tree parameter)
> >   {
> >     tree type = TREE_TYPE (parameter);
> > +  value_range r;
> >     wide_int min, max;
> >
> >     gcc_assert (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type));
> >
> >     if (INTEGRAL_TYPE_P (type)
> > -      && get_range_info (parameter, &min, &max) == VR_RANGE)
> > -    ;
> > +      && RANGE_QUERY (cfun)->range_of_expr (r, parameter)
> > +      && !r.undefined_p ())
> > +    {
> > +      min = r.lower_bound ();
> > +      max = r.upper_bound ();
> > +    }
> >     else
> >       {
> >         min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
> > diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
> > index d209a52f823..dd1f204863e 100644
> > --- a/gcc/internal-fn.c
> > +++ b/gcc/internal-fn.c
> > @@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "ssa-iterators.h"
> >   #include "explow.h"
> >   #include "rtl-iter.h"
> > +#include "gimple-range.h"
> >
> >   /* The names of each internal function, indexed by function number.  */
> >   const char *const internal_fn_name_array[] = {
> > @@ -680,8 +681,9 @@ get_min_precision (tree arg, signop sign)
> >       }
> >     if (TREE_CODE (arg) != SSA_NAME)
> >       return prec + (orig_sign != sign);
> > -  wide_int arg_min, arg_max;
> > -  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
> > +  value_range r;
> > +  while (!GLOBAL_RANGE_QUERY->range_of_expr (r, arg)
> > +      || r.kind () != VR_RANGE)
> >       {
> >         gimple *g = SSA_NAME_DEF_STMT (arg);
> >         if (is_gimple_assign (g)
> > @@ -709,14 +711,14 @@ get_min_precision (tree arg, signop sign)
> >       }
> >     if (sign == TYPE_SIGN (TREE_TYPE (arg)))
> >       {
> > -      int p1 = wi::min_precision (arg_min, sign);
> > -      int p2 = wi::min_precision (arg_max, sign);
> > +      int p1 = wi::min_precision (r.lower_bound (), sign);
> > +      int p2 = wi::min_precision (r.upper_bound (), sign);
> >         p1 = MAX (p1, p2);
> >         prec = MIN (prec, p1);
> >       }
> > -  else if (sign == UNSIGNED && !wi::neg_p (arg_min, SIGNED))
> > +  else if (sign == UNSIGNED && !wi::neg_p (r.lower_bound (), SIGNED))
> >       {
> > -      int p = wi::min_precision (arg_max, UNSIGNED);
> > +      int p = wi::min_precision (r.upper_bound (), UNSIGNED);
> >         prec = MIN (prec, p);
> >       }
> >     return prec + (orig_sign != sign);
> > diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
> > index 4e5be812734..299d7fc1f60 100644
> > --- a/gcc/ipa-fnsummary.c
> > +++ b/gcc/ipa-fnsummary.c
> > @@ -85,6 +85,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "attribs.h"
> >   #include "tree-into-ssa.h"
> >   #include "symtab-clones.h"
> > +#include "gimple-range.h"
> >
> >   /* Summaries.  */
> >   fast_function_summary <ipa_fn_summary *, va_gc> *ipa_fn_summaries;
> > @@ -1687,8 +1688,14 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
> >     int bound_limit = opt_for_fn (fbi->node->decl,
> >                               param_ipa_max_switch_predicate_bounds);
> >     int bound_count = 0;
> > -  wide_int vr_wmin, vr_wmax;
> > -  value_range_kind vr_type = get_range_info (op, &vr_wmin, &vr_wmax);
> > +  value_range vr;
> > +
> > +  RANGE_QUERY (cfun)->range_of_expr (vr, op);
> > +  if (vr.undefined_p ())
> > +    vr.set_varying (TREE_TYPE (op));
> > +  value_range_kind vr_type = vr.kind ();
> > +  wide_int vr_wmin = wi::to_wide (vr.min ());
> > +  wide_int vr_wmax = wi::to_wide (vr.max ());
> >
> >     FOR_EACH_EDGE (e, ei, bb->succs)
> >       {
> > diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
> > index 0591ef1b569..02f422bdbf3 100644
> > --- a/gcc/ipa-prop.c
> > +++ b/gcc/ipa-prop.c
> > @@ -55,6 +55,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "options.h"
> >   #include "symtab-clones.h"
> >   #include "attr-fnspec.h"
> > +#include "gimple-range.h"
> >
> >   /* Function summary where the parameter infos are actually stored. */
> >   ipa_node_params_t *ipa_node_params_sum = NULL;
> > @@ -2237,6 +2238,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
> >     gcall *call = cs->call_stmt;
> >     int n, arg_num = gimple_call_num_args (call);
> >     bool useful_context = false;
> > +  value_range vr;
> >
> >     if (arg_num == 0 || args->jump_functions)
> >       return;
> > @@ -2274,7 +2276,8 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
> >
> >         if (TREE_CODE (arg) == SSA_NAME
> >             && param_type
> > -           && get_ptr_nonnull (arg))
> > +           && RANGE_QUERY (cfun)->range_of_expr (vr, arg)
> > +           && vr.nonzero_p ())
> >           addr_nonzero = true;
> >         else if (tree_single_nonzero_warnv_p (arg, &strict_overflow))
> >           addr_nonzero = true;
> > @@ -2289,19 +2292,14 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
> >       }
> >         else
> >       {
> > -       wide_int min, max;
> > -       value_range_kind kind;
> >         if (TREE_CODE (arg) == SSA_NAME
> >             && param_type
> > -           && (kind = get_range_info (arg, &min, &max))
> > -           && (kind == VR_RANGE || kind == VR_ANTI_RANGE))
> > +           && RANGE_QUERY (cfun)->range_of_expr (vr, arg)
> > +           && !vr.undefined_p ())
> >           {
> >             value_range resvr;
> > -           value_range tmpvr (wide_int_to_tree (TREE_TYPE (arg), min),
> > -                              wide_int_to_tree (TREE_TYPE (arg), max),
> > -                              kind);
> >             range_fold_unary_expr (&resvr, NOP_EXPR, param_type,
> > -                                  &tmpvr, TREE_TYPE (arg));
> > +                                  &vr, TREE_TYPE (arg));
> >             if (!resvr.undefined_p () && !resvr.varying_p ())
> >               ipa_set_jfunc_vr (jfunc, &resvr);
> >             else
> > diff --git a/gcc/match.pd b/gcc/match.pd
> > index cdb87636951..9dddf5ebd0a 100644
> > --- a/gcc/match.pd
> > +++ b/gcc/match.pd
> > @@ -663,11 +663,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> >       (with
> >        {
> >          bool overflowed = true;
> > -       wide_int wmin0, wmax0, wmin1, wmax1;
> > +       value_range vr0, vr1;
> >          if (INTEGRAL_TYPE_P (type)
> > -        && get_range_info (@0, &wmin0, &wmax0) == VR_RANGE
> > -        && get_range_info (@1, &wmin1, &wmax1) == VR_RANGE)
> > +        && GLOBAL_RANGE_QUERY->range_of_expr (vr0, @0)
> > +        && GLOBAL_RANGE_QUERY->range_of_expr (vr1, @1)
> > +        && vr0.kind () == VR_RANGE
> > +        && vr1.kind () == VR_RANGE)
> >        {
> > +        wide_int wmin0 = vr0.lower_bound ();
> > +        wide_int wmax0 = vr0.upper_bound ();
> > +        wide_int wmin1 = vr1.lower_bound ();
> > +        wide_int wmax1 = vr1.upper_bound ();
> >          /* If the multiplication can't overflow/wrap around, then
> >             it can be optimized too.  */
> >          wi::overflow_type min_ovf, max_ovf;
> > @@ -2509,9 +2515,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> >         = wide_int::from (wi::to_wide (@1), TYPE_PRECISION (inner_type),
> >                           TYPE_SIGN (inner_type));
> >
> > -        wide_int wmin0, wmax0;
> > -        if (get_range_info (@0, &wmin0, &wmax0) == VR_RANGE)
> > +     value_range vr;
> > +     if (GLOBAL_RANGE_QUERY->range_of_expr (vr, @0)
> > +         && vr.kind () == VR_RANGE)
> >             {
> > +         wide_int wmin0 = vr.lower_bound ();
> > +         wide_int wmax0 = vr.upper_bound ();
> >               wi::add (wmin0, w1, TYPE_SIGN (inner_type), &min_ovf);
> >               wi::add (wmax0, w1, TYPE_SIGN (inner_type), &max_ovf);
> >             }
> > diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
> > index e6dd5f15bed..5ba41e2c73d 100644
> > --- a/gcc/tree-data-ref.c
> > +++ b/gcc/tree-data-ref.c
> > @@ -1035,14 +1035,23 @@ split_constant_offset (tree exp, tree *var, tree *off, value_range *exp_range,
> >         *exp_range = type;
> >         if (code == SSA_NAME)
> >       {
> > -       wide_int var_min, var_max;
> > -       value_range_kind vr_kind = get_range_info (exp, &var_min, &var_max);
> > +       value_range vr;
> > +       RANGE_QUERY (cfun)->range_of_expr (vr, exp);
> > +       if (vr.undefined_p ())
> > +         vr.set_varying (TREE_TYPE (exp));
> > +       wide_int var_min = wi::to_wide (vr.min ());
> > +       wide_int var_max = wi::to_wide (vr.max ());
> > +       value_range_kind vr_kind = vr.kind ();
> >         wide_int var_nonzero = get_nonzero_bits (exp);
> >         vr_kind = intersect_range_with_nonzero_bits (vr_kind,
> >                                                      &var_min, &var_max,
> >                                                      var_nonzero,
> >                                                      TYPE_SIGN (type));
> > -       if (vr_kind == VR_RANGE)
> > +       /* This check for VR_VARYING is here because the old code
> > +          using get_range_info would return VR_RANGE for the entire
> > +          domain, instead of VR_VARYING.  The new code normalizes
> > +          full-domain ranges to VR_VARYING.  */
> > +       if (vr_kind == VR_RANGE || vr_kind == VR_VARYING)
> >           *exp_range = value_range (type, var_min, var_max);
> >       }
> >       }
> > @@ -6298,12 +6307,19 @@ dr_step_indicator (struct data_reference *dr, int useful_min)
> >
> >         /* Get the range of values that the unconverted step actually has.  */
> >         wide_int step_min, step_max;
> > +      value_range vr;
> >         if (TREE_CODE (step) != SSA_NAME
> > -       || get_range_info (step, &step_min, &step_max) != VR_RANGE)
> > +       || !RANGE_QUERY (cfun)->range_of_expr (vr, step)
> > +       || vr.kind () != VR_RANGE)
> >       {
> >         step_min = wi::to_wide (TYPE_MIN_VALUE (type));
> >         step_max = wi::to_wide (TYPE_MAX_VALUE (type));
> >       }
> > +      else
> > +     {
> > +       step_min = vr.lower_bound ();
> > +       step_max = vr.upper_bound ();
> > +     }
> >
> >         /* Check whether the unconverted step has an acceptable range.  */
> >         signop sgn = TYPE_SIGN (type);
> > diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
> > index 0482b05e26c..e9cf4bfa706 100644
> > --- a/gcc/tree-dfa.c
> > +++ b/gcc/tree-dfa.c
> > @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "gimple-iterator.h"
> >   #include "gimple-walk.h"
> >   #include "tree-dfa.h"
> > +#include "gimple-range.h"
> >
> >   /* Build and maintain data flow information for trees.  */
> >
> > @@ -530,14 +531,23 @@ get_ref_base_and_extent (tree exp, poly_int64_pod *poffset,
> >                  index.  */
> >               seen_variable_array_ref = true;
> >
> > -             wide_int min, max;
> > +             value_range vr;
> > +             range_query *query;
> > +             if (cfun)
> > +               query = RANGE_QUERY (cfun);
> > +             else
> > +               query = GLOBAL_RANGE_QUERY;
> > +
> >               if (TREE_CODE (index) == SSA_NAME
> >                   && (low_bound = array_ref_low_bound (exp),
> >                       poly_int_tree_p (low_bound))
> >                   && (unit_size = array_ref_element_size (exp),
> >                       TREE_CODE (unit_size) == INTEGER_CST)
> > -                 && get_range_info (index, &min, &max) == VR_RANGE)
> > +                 && query->range_of_expr (vr, index)
> > +                 && vr.kind () == VR_RANGE)
> >                 {
> > +                 wide_int min = vr.lower_bound ();
> > +                 wide_int max = vr.upper_bound ();
> >                   poly_offset_int lbound = wi::to_poly_offset (low_bound);
> >                   /* Try to constrain maxsize with range information.  */
> >                   offset_int omax
> > diff --git a/gcc/tree-scalar-evolution.c b/gcc/tree-scalar-evolution.c
> > index ff052be1021..f0f28f26042 100644
> > --- a/gcc/tree-scalar-evolution.c
> > +++ b/gcc/tree-scalar-evolution.c
> > @@ -3039,18 +3039,27 @@ iv_can_overflow_p (class loop *loop, tree type, tree base, tree step)
> >     widest_int nit;
> >     wide_int base_min, base_max, step_min, step_max, type_min, type_max;
> >     signop sgn = TYPE_SIGN (type);
> > +  value_range r;
> >
> >     if (integer_zerop (step))
> >       return false;
> >
> >     if (!INTEGRAL_TYPE_P (TREE_TYPE (base))
> > -      || get_range_info (base, &base_min, &base_max) != VR_RANGE)
> > +      || !RANGE_QUERY (cfun)->range_of_expr (r, base)
> > +      || r.kind () != VR_RANGE)
> >       return true;
> >
> > +  base_min = r.lower_bound ();
> > +  base_max = r.upper_bound ();
> > +
> >     if (!INTEGRAL_TYPE_P (TREE_TYPE (step))
> > -      || get_range_info (step, &step_min, &step_max) != VR_RANGE)
> > +      || !RANGE_QUERY (cfun)->range_of_expr (r, step)
> > +      || r.kind () != VR_RANGE)
> >       return true;
> >
> > +  step_min = r.lower_bound ();
> > +  step_max = r.upper_bound ();
> > +
> >     if (!get_max_loop_iterations (loop, &nit))
> >       return true;
> >
> > diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
> > index 3817ec423e7..bfbb11c59c5 100644
> > --- a/gcc/tree-ssa-loop-niter.c
> > +++ b/gcc/tree-ssa-loop-niter.c
> > @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "tree-chrec.h"
> >   #include "tree-scalar-evolution.h"
> >   #include "tree-dfa.h"
> > +#include "gimple-range.h"
> >
> >
> >   /* The maximum number of dominator BBs we search for conditions
> > @@ -121,7 +122,6 @@ refine_value_range_using_guard (tree type, tree var,
> >     tree varc0, varc1, ctype;
> >     mpz_t offc0, offc1;
> >     mpz_t mint, maxt, minc1, maxc1;
> > -  wide_int minv, maxv;
> >     bool no_wrap = nowrap_type_p (type);
> >     bool c0_ok, c1_ok;
> >     signop sgn = TYPE_SIGN (type);
> > @@ -221,6 +221,7 @@ refine_value_range_using_guard (tree type, tree var,
> >     get_type_static_bounds (type, mint, maxt);
> >     mpz_init (minc1);
> >     mpz_init (maxc1);
> > +  value_range r;
> >     /* Setup range information for varc1.  */
> >     if (integer_zerop (varc1))
> >       {
> > @@ -229,11 +230,12 @@ refine_value_range_using_guard (tree type, tree var,
> >       }
> >     else if (TREE_CODE (varc1) == SSA_NAME
> >          && INTEGRAL_TYPE_P (type)
> > -        && get_range_info (varc1, &minv, &maxv) == VR_RANGE)
> > +        && RANGE_QUERY (cfun)->range_of_expr (r, varc1)
> > +        && r.kind () == VR_RANGE)
> >       {
> > -      gcc_assert (wi::le_p (minv, maxv, sgn));
> > -      wi::to_mpz (minv, minc1, sgn);
> > -      wi::to_mpz (maxv, maxc1, sgn);
> > +      gcc_assert (wi::le_p (r.lower_bound (), r.upper_bound (), sgn));
> > +      wi::to_mpz (r.lower_bound (), minc1, sgn);
> > +      wi::to_mpz (r.upper_bound (), maxc1, sgn);
> >       }
> >     else
> >       {
> > @@ -372,34 +374,50 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
> >         gphi_iterator gsi;
> >
> >         /* Either for VAR itself...  */
> > -      rtype = get_range_info (var, &minv, &maxv);
> > +      value_range var_range;
> > +      RANGE_QUERY (cfun)->range_of_expr (var_range, var);
> > +      rtype = var_range.kind ();
> > +      if (!var_range.undefined_p ())
> > +     {
> > +       minv = var_range.lower_bound ();
> > +       maxv = var_range.upper_bound ();
> > +     }
> > +
> >         /* Or for PHI results in loop->header where VAR is used as
> >        PHI argument from the loop preheader edge.  */
> >         for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi))
> >       {
> >         gphi *phi = gsi.phi ();
> > -       wide_int minc, maxc;
> > +       value_range phi_range;
> >         if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var
> > -           && (get_range_info (gimple_phi_result (phi), &minc, &maxc)
> > -               == VR_RANGE))
> > +           && RANGE_QUERY (cfun)->range_of_expr (phi_range,
> > +                                                 gimple_phi_result (phi))
> > +           && phi_range.kind () == VR_RANGE)
> >           {
> >             if (rtype != VR_RANGE)
> >               {
> >                 rtype = VR_RANGE;
> > -               minv = minc;
> > -               maxv = maxc;
> > +               minv = phi_range.lower_bound ();
> > +               maxv = phi_range.upper_bound ();
> >               }
> >             else
> >               {
> > -               minv = wi::max (minv, minc, sgn);
> > -               maxv = wi::min (maxv, maxc, sgn);
> > +               minv = wi::max (minv, phi_range.lower_bound (), sgn);
> > +               maxv = wi::min (maxv, phi_range.upper_bound (), sgn);
> >                 /* If the PHI result range are inconsistent with
> >                    the VAR range, give up on looking at the PHI
> >                    results.  This can happen if VR_UNDEFINED is
> >                    involved.  */
> >                 if (wi::gt_p (minv, maxv, sgn))
> >                   {
> > -                   rtype = get_range_info (var, &minv, &maxv);
> > +                   value_range vr;
> > +                   RANGE_QUERY (cfun)->range_of_expr (vr, var);
> > +                   rtype = vr.kind ();
> > +                   if (!vr.undefined_p ())
> > +                     {
> > +                       minv = vr.lower_bound ();
> > +                       maxv = vr.upper_bound ();
> > +                     }
> >                     break;
> >                   }
> >               }
> > @@ -3545,12 +3563,16 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
> >
> >     if (tree_int_cst_sign_bit (step))
> >       {
> > -      wide_int min, max;
> > +      wide_int max;
> > +      value_range base_range;
> > +      if (RANGE_QUERY (cfun)->range_of_expr (base_range, orig_base)
> > +       && !base_range.undefined_p ())
> > +     max = base_range.upper_bound ();
> >         extreme = fold_convert (unsigned_type, low);
> >         if (TREE_CODE (orig_base) == SSA_NAME
> >         && TREE_CODE (high) == INTEGER_CST
> >         && INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
> > -       && (get_range_info (orig_base, &min, &max) == VR_RANGE
> > +       && (base_range.kind () == VR_RANGE
> >             || get_cst_init_from_scev (orig_base, &max, false))
> >         && wi::gts_p (wi::to_wide (high), max))
> >       base = wide_int_to_tree (unsigned_type, max);
> > @@ -3563,12 +3585,16 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
> >       }
> >     else
> >       {
> > -      wide_int min, max;
> > +      wide_int min;
> > +      value_range base_range;
> > +      if (RANGE_QUERY (cfun)->range_of_expr (base_range, orig_base)
> > +       && !base_range.undefined_p ())
> > +     min = base_range.lower_bound ();
> >         extreme = fold_convert (unsigned_type, high);
> >         if (TREE_CODE (orig_base) == SSA_NAME
> >         && TREE_CODE (low) == INTEGER_CST
> >         && INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
> > -       && (get_range_info (orig_base, &min, &max) == VR_RANGE
> > +       && (base_range.kind () == VR_RANGE
> >             || get_cst_init_from_scev (orig_base, &min, true))
> >         && wi::gts_p (min, wi::to_wide (low)))
> >       base = wide_int_to_tree (unsigned_type, min);
> > @@ -3835,11 +3861,12 @@ infer_loop_bounds_from_signedness (class loop *loop, gimple *stmt)
> >
> >     low = lower_bound_in_type (type, type);
> >     high = upper_bound_in_type (type, type);
> > -  wide_int minv, maxv;
> > -  if (get_range_info (def, &minv, &maxv) == VR_RANGE)
> > +  value_range r;
> > +  RANGE_QUERY (cfun)->range_of_expr (r, def);
> > +  if (r.kind () == VR_RANGE)
> >       {
> > -      low = wide_int_to_tree (type, minv);
> > -      high = wide_int_to_tree (type, maxv);
> > +      low = wide_int_to_tree (type, r.lower_bound ());
> > +      high = wide_int_to_tree (type, r.upper_bound ());
> >       }
> >
> >     record_nonwrapping_iv (loop, base, step, stmt, low, high, false, true);
> > @@ -4873,7 +4900,6 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
> >   {
> >     tree type;
> >     wide_int minv, maxv, diff, step_wi;
> > -  enum value_range_kind rtype;
> >
> >     if (TREE_CODE (step) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (var)))
> >       return false;
> > @@ -4884,8 +4910,9 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
> >     if (!def_bb || !dominated_by_p (CDI_DOMINATORS, loop->latch, def_bb))
> >       return false;
> >
> > -  rtype = get_range_info (var, &minv, &maxv);
> > -  if (rtype != VR_RANGE)
> > +  value_range r;
> > +  RANGE_QUERY (cfun)->range_of_expr (r, var);
> > +  if (r.kind () != VR_RANGE)
> >       return false;
> >
> >     /* VAR is a scev whose evolution part is STEP and value range info
> > @@ -4899,11 +4926,11 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
> >     type = TREE_TYPE (var);
> >     if (tree_int_cst_sign_bit (step))
> >       {
> > -      diff = minv - wi::to_wide (lower_bound_in_type (type, type));
> > +      diff = r.lower_bound () - wi::to_wide (lower_bound_in_type (type, type));
> >         step_wi = - step_wi;
> >       }
> >     else
> > -    diff = wi::to_wide (upper_bound_in_type (type, type)) - maxv;
> > +    diff = wi::to_wide (upper_bound_in_type (type, type)) - r.upper_bound ();
> >
> >     return (wi::geu_p (diff, step_wi));
> >   }
> > diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
> > index 8e8a08bc679..d464c84f164 100644
> > --- a/gcc/tree-ssa-phiopt.c
> > +++ b/gcc/tree-ssa-phiopt.c
> > @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "tree-eh.h"
> >   #include "gimple-fold.h"
> >   #include "internal-fn.h"
> > +#include "gimple-range.h"
> >
> >   static unsigned int tree_ssa_phiopt_worker (bool, bool, bool);
> >   static bool two_value_replacement (basic_block, basic_block, edge, gphi *,
> > @@ -684,7 +685,15 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb,
> >       return false;
> >
> >     wide_int min, max;
> > -  if (get_range_info (lhs, &min, &max) != VR_RANGE)
> > +  value_range r;
> > +  RANGE_QUERY (cfun)->range_of_expr (r, lhs);
> > +
> > +  if (r.kind () == VR_RANGE)
> > +    {
> > +      min = r.lower_bound ();
> > +      max = r.upper_bound ();
> > +    }
> > +  else
> >       {
> >         int prec = TYPE_PRECISION (TREE_TYPE (lhs));
> >         signop sgn = TYPE_SIGN (TREE_TYPE (lhs));
> > diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
> > index 2d22535af87..870d3cba9ff 100644
> > --- a/gcc/tree-ssa-pre.c
> > +++ b/gcc/tree-ssa-pre.c
> > @@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "tree-ssa-dce.h"
> >   #include "tree-cfgcleanup.h"
> >   #include "alias.h"
> > +#include "gimple-range.h"
> >
> >   /* Even though this file is called tree-ssa-pre.c, we actually
> >      implement a bit more than just PRE here.  All of them piggy-back
> > @@ -3234,16 +3235,18 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
> >         >= TYPE_PRECISION (TREE_TYPE (expr->u.nary->op[0])))
> >         && SSA_NAME_RANGE_INFO (expr->u.nary->op[0]))
> >       {
> > -      wide_int min, max;
> > -      if (get_range_info (expr->u.nary->op[0], &min, &max) == VR_RANGE
> > -       && !wi::neg_p (min, SIGNED)
> > -       && !wi::neg_p (max, SIGNED))
> > +      value_range r;
> > +      if (RANGE_QUERY (cfun)->range_of_expr (r, expr->u.nary->op[0])
> > +       && r.kind () == VR_RANGE
> > +       && !wi::neg_p (r.lower_bound (), SIGNED)
> > +       && !wi::neg_p (r.upper_bound (), SIGNED))
> >       /* Just handle extension and sign-changes of all-positive ranges.  */
> > -     set_range_info (temp,
> > -                     SSA_NAME_RANGE_TYPE (expr->u.nary->op[0]),
> > -                     wide_int_storage::from (min, TYPE_PRECISION (type),
> > +     set_range_info (temp, VR_RANGE,
> > +                     wide_int_storage::from (r.lower_bound (),
> > +                                             TYPE_PRECISION (type),
> >                                               TYPE_SIGN (type)),
> > -                     wide_int_storage::from (max, TYPE_PRECISION (type),
> > +                     wide_int_storage::from (r.upper_bound (),
> > +                                             TYPE_PRECISION (type),
> >                                               TYPE_SIGN (type)));
> >       }
> >
> > diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
> > index 32e1632705b..cc098369e2e 100644
> > --- a/gcc/tree-ssa-reassoc.c
> > +++ b/gcc/tree-ssa-reassoc.c
> > @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "case-cfn-macros.h"
> >   #include "tree-ssa-reassoc.h"
> >   #include "tree-ssa-math-opts.h"
> > +#include "gimple-range.h"
> >
> >   /*  This is a simple global reassociation pass.  It is, in part, based
> >       on the LLVM pass of the same name (They do some things more/less
> > @@ -3221,12 +3222,14 @@ optimize_range_tests_to_bit_test (enum tree_code opcode, int first, int length,
> >        amount, then we can merge the entry test in the bit test.  In this
> >        case, if we would need otherwise 2 or more comparisons, then use
> >        the bit test; in the other cases, the threshold is 3 comparisons.  */
> > -      wide_int min, max;
> >         bool entry_test_needed;
> > +      value_range r;
> >         if (TREE_CODE (exp) == SSA_NAME
> > -       && get_range_info (exp, &min, &max) == VR_RANGE
> > -       && wi::leu_p (max - min, prec - 1))
> > +       && RANGE_QUERY (cfun)->range_of_expr (r, exp)
> > +       && r.kind () == VR_RANGE
> > +       && wi::leu_p (r.upper_bound () - r.lower_bound (), prec - 1))
> >       {
> > +       wide_int min = r.lower_bound ();
> >         wide_int ilowi = wi::to_wide (lowi);
> >         if (wi::lt_p (min, ilowi, TYPE_SIGN (TREE_TYPE (lowi))))
> >           {
> > diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
> > index c7b5e2c6e6b..2f85a609107 100644
> > --- a/gcc/tree-ssa-strlen.c
> > +++ b/gcc/tree-ssa-strlen.c
> > @@ -196,7 +196,7 @@ static void handle_builtin_stxncpy_strncat (bool, gimple_stmt_iterator *);
> >   /* Sets MINMAX to either the constant value or the range VAL is in
> >      and returns either the constant value or VAL on success or null
> >      when the range couldn't be determined.  Uses RVALS when nonnull
> > -   to determine the range, otherwise get_range_info.  */
> > +   to determine the range, otherwise uses global range info.  */
> >
> >   tree
> >   get_range (tree val, gimple *stmt, wide_int minmax[2],
> > @@ -211,9 +211,9 @@ get_range (tree val, gimple *stmt, wide_int minmax[2],
> >     if (TREE_CODE (val) != SSA_NAME)
> >       return NULL_TREE;
> >
> > +  value_range vr;
> >     if (rvals && stmt)
> >       {
> > -      value_range vr;
> >         if (!rvals->range_of_expr (vr, val, stmt))
> >       return NULL_TREE;
> >         value_range_kind rng = vr.kind ();
> > @@ -225,7 +225,15 @@ get_range (tree val, gimple *stmt, wide_int minmax[2],
> >         return val;
> >       }
> >
> > -  value_range_kind rng = get_range_info (val, minmax, minmax + 1);
> > +  // ?? This entire function should use RANGE_QUERY or GLOBAL_RANGE_QUERY,
> > +  // instead of doing something different for RVALS and global ranges.
> > +
> > +  if (!GLOBAL_RANGE_QUERY->range_of_expr (vr, val) || vr.undefined_p ())
> > +    return NULL_TREE;
> > +
> > +  minmax[0] = wi::to_wide (vr.min ());
> > +  minmax[1] = wi::to_wide (vr.max ());
> > +  value_range_kind rng = vr.kind ();
> >     if (rng == VR_RANGE)
> >       /* This may be an inverted range whose MINMAX[1] < MINMAX[0].  */
> >       return val;
> > @@ -929,7 +937,17 @@ dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals)
> >                           rng = VR_UNDEFINED;
> >                       }
> >                     else
> > -                     rng = get_range_info (si->nonzero_chars, &min, &max);
> > +                     {
> > +                       value_range vr;
> > +                       GLOBAL_RANGE_QUERY->range_of_expr (vr,
> > +                                                          si->nonzero_chars);
> > +                       rng = vr.kind ();
> > +                       if (!vr.undefined_p ())
> > +                         {
> > +                           min = wi::to_wide (vr.min ());
> > +                           max = wi::to_wide (vr.max ());
> > +                         }
> > +                     }
> >
> >                     if (rng == VR_RANGE || rng == VR_ANTI_RANGE)
> >                       {
> > @@ -1809,18 +1827,17 @@ set_strlen_range (tree lhs, wide_int min, wide_int max,
> >       }
> >         else if (TREE_CODE (bound) == SSA_NAME)
> >       {
> > -       wide_int minbound, maxbound;
> > -       // FIXME: Use range_query instead of global ranges.
> > -       value_range_kind rng = get_range_info (bound, &minbound, &maxbound);
> > -       if (rng == VR_RANGE)
> > +       value_range r;
> > +       RANGE_QUERY (cfun)->range_of_expr (r, bound);
> > +       if (!r.undefined_p ())
> >           {
> >             /* For a bound in a known range, adjust the range determined
> >                above as necessary.  For a bound in some anti-range or
> >                in an unknown range, use the range determined by callers.  */
> > -           if (wi::ltu_p (minbound, min))
> > -             min = minbound;
> > -           if (wi::ltu_p (maxbound, max))
> > -             max = maxbound;
> > +           if (wi::ltu_p (r.lower_bound (), min))
> > +             min = r.lower_bound ();
> > +           if (wi::ltu_p (r.upper_bound (), max))
> > +             max = r.upper_bound ();
> >           }
> >       }
> >       }
> > @@ -2780,12 +2797,15 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt,
> >       return false;
> >
> >     wide_int cntrange[2];
> > +  value_range r;
> > +  if (!RANGE_QUERY (cfun)->range_of_expr (r, cnt)
> > +      || r.varying_p ()
> > +      || r.undefined_p ())
> > +    return false;
> >
> > -  // FIXME: Use range_query instead of global ranges.
> > -  enum value_range_kind rng = get_range_info (cnt, cntrange, cntrange + 1);
> > -  if (rng == VR_RANGE)
> > -    ;
> > -  else if (rng == VR_ANTI_RANGE)
> > +  cntrange[0] = wi::to_wide (r.min ());
> > +  cntrange[1] = wi::to_wide (r.max ());
> > +  if (r.kind () == VR_ANTI_RANGE)
> >       {
> >         wide_int maxobjsize = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
> >
> > @@ -2800,8 +2820,6 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt,
> >         cntrange[0] = wi::zero (TYPE_PRECISION (TREE_TYPE (cnt)));
> >       }
> >       }
> > -  else
> > -    return false;
> >
> >     /* Negative value is the constant string length.  If it's less than
> >        the lower bound there is no truncation.  Avoid calling get_stridx()
> > @@ -3923,13 +3941,12 @@ get_len_or_size (gimple *stmt, tree arg, int idx,
> >       }
> >         else if (TREE_CODE (si->nonzero_chars) == SSA_NAME)
> >       {
> > -       wide_int min, max;
> > -       // FIXME: Use range_query instead of global ranges.
> > -       value_range_kind rng = get_range_info (si->nonzero_chars, &min, &max);
> > -       if (rng == VR_RANGE)
> > +       value_range r;
> > +       RANGE_QUERY (cfun)->range_of_expr (r, si->nonzero_chars);
> > +       if (r.kind () == VR_RANGE)
> >           {
> > -           lenrng[0] = min.to_uhwi ();
> > -           lenrng[1] = max.to_uhwi ();
> > +           lenrng[0] = r.lower_bound ().to_uhwi ();
> > +           lenrng[1] = r.upper_bound ().to_uhwi ();
> >             *nulterm = si->full_string_p;
> >           }
> >       }
> > @@ -5301,17 +5318,13 @@ handle_integral_assign (gimple_stmt_iterator *gsi, bool *cleanup_eh,
> >                 /* Reading a character before the final '\0'
> >                    character.  Just set the value range to ~[0, 0]
> >                    if we don't have anything better.  */
> > -               wide_int min, max;
> > -               signop sign = TYPE_SIGN (lhs_type);
> > -               int prec = TYPE_PRECISION (lhs_type);
> > -               // FIXME: Use range_query instead of global ranges.
> > -               value_range_kind vr = get_range_info (lhs, &min, &max);
> > -               if (vr == VR_VARYING
> > -                   || (vr == VR_RANGE
> > -                       && min == wi::min_value (prec, sign)
> > -                       && max == wi::max_value (prec, sign)))
> > -                 set_range_info (lhs, VR_ANTI_RANGE,
> > -                                 wi::zero (prec), wi::zero (prec));
> > +               value_range r;
> > +               if (!RANGE_QUERY (cfun)->range_of_expr (r, lhs)
> > +                   || r.varying_p ())
> > +                 {
> > +                   r.set_nonzero (lhs_type);
> > +                   set_range_info (lhs, r);
> > +                 }
> >               }
> >           }
> >       }
> > diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
> > index a0238710e72..514cec1d927 100644
> > --- a/gcc/tree-ssa-structalias.c
> > +++ b/gcc/tree-ssa-structalias.c
> > @@ -43,6 +43,7 @@
> >   #include "attribs.h"
> >   #include "tree-ssa.h"
> >   #include "tree-cfg.h"
> > +#include "gimple-range.h"
> >
> >   /* The idea behind this analyzer is to generate set constraints from the
> >      program, then solve the resulting constraints in order to generate the
> > @@ -6740,7 +6741,9 @@ find_what_p_points_to (tree fndecl, tree p)
> >     struct ptr_info_def *pi;
> >     tree lookup_p = p;
> >     varinfo_t vi;
> > -  bool nonnull = get_ptr_nonnull (p);
> > +  value_range vr;
> > +  GLOBAL_RANGE_QUERY->range_of_expr (vr, p);
> > +  bool nonnull = vr.nonzero_p ();
> >
> >     /* For parameters, get at the points-to set for the actual parm
> >        decl.  */
> > @@ -6758,8 +6761,7 @@ find_what_p_points_to (tree fndecl, tree p)
> >     pi->pt = find_what_var_points_to (fndecl, vi);
> >     /* Conservatively set to NULL from PTA (to true). */
> >     pi->pt.null = 1;
> > -  /* Preserve pointer nonnull computed by VRP.  See get_ptr_nonnull
> > -     in gcc/tree-ssaname.c for more information.  */
> > +  /* Preserve pointer nonnull globally computed.  */
> >     if (nonnull)
> >       set_ptr_nonnull (p);
> >   }
> > diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
> > index f55ce1939ac..b352f68b1b7 100644
> > --- a/gcc/tree-ssa-uninit.c
> > +++ b/gcc/tree-ssa-uninit.c
> > @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "attribs.h"
> >   #include "builtins.h"
> >   #include "calls.h"
> > +#include "gimple-range.h"
> >
> >   /* This implements the pass that does predicate aware warning on uses of
> >      possibly uninitialized variables.  The pass first collects the set of
> > @@ -1606,11 +1607,14 @@ find_var_cmp_const (pred_chain_union preds, gphi *phi, gimple **flag_def,
> >              flag_var <= [min, max] ->  flag_var < [min, max+1]
> >              flag_var >= [min, max] ->  flag_var > [min-1, max]
> >            if no overflow/wrap.  */
> > -       wide_int min, max;
> >         tree type = TREE_TYPE (cond_lhs);
> > +       value_range r;
> >         if (!INTEGRAL_TYPE_P (type)
> > -           || get_range_info (cond_rhs, &min, &max) != VR_RANGE)
> > +           || !RANGE_QUERY (cfun)->range_of_expr (r, cond_rhs)
> > +           || r.kind () != VR_RANGE)
> >           continue;
> > +       wide_int min = r.lower_bound ();
> > +       wide_int max = r.upper_bound ();
> >         if (code == LE_EXPR
> >             && max != wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)))
> >           {
> > diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
> > index 7f65c4ce839..225d831003f 100644
> > --- a/gcc/tree-switch-conversion.c
> > +++ b/gcc/tree-switch-conversion.c
> > @@ -50,6 +50,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
> >   #include "target.h"
> >   #include "tree-into-ssa.h"
> >   #include "omp-general.h"
> > +#include "gimple-range.h"
> >
> >   /* ??? For lang_hooks.types.type_for_mode, but is there a word_mode
> >      type in the GIMPLE type system that is language-independent?  */
> > @@ -1553,12 +1554,15 @@ bit_test_cluster::emit (tree index_expr, tree index_type,
> >
> >     /* If every possible relative value of the index expression is a valid shift
> >        amount, then we can merge the entry test in the bit test.  */
> > -  wide_int min, max;
> >     bool entry_test_needed;
> > +  value_range r;
> >     if (TREE_CODE (index_expr) == SSA_NAME
> > -      && get_range_info (index_expr, &min, &max) == VR_RANGE
> > -      && wi::leu_p (max - min, prec - 1))
> > +      && RANGE_QUERY (cfun)->range_of_expr (r, index_expr)
> > +      && r.kind () == VR_RANGE
> > +      && wi::leu_p (r.upper_bound () - r.lower_bound (), prec - 1))
> >       {
> > +      wide_int min = r.lower_bound ();
> > +      wide_int max = r.upper_bound ();
> >         tree index_type = TREE_TYPE (index_expr);
> >         minval = fold_convert (index_type, minval);
> >         wide_int iminval = wi::to_wide (minval);
> > diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
> > index 803de3fc287..99be2314029 100644
> > --- a/gcc/tree-vect-patterns.c
> > +++ b/gcc/tree-vect-patterns.c
> > @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "predict.h"
> >   #include "tree-vector-builder.h"
> >   #include "vec-perm-indices.h"
> > +#include "gimple-range.h"
> >
> >   /* Return true if we have a useful VR_RANGE range for VAR, storing it
> >      in *MIN_VALUE and *MAX_VALUE if so.  Note the range in the dump files.  */
> > @@ -55,7 +56,13 @@ along with GCC; see the file COPYING3.  If not see
> >   static bool
> >   vect_get_range_info (tree var, wide_int *min_value, wide_int *max_value)
> >   {
> > -  value_range_kind vr_type = get_range_info (var, min_value, max_value);
> > +  value_range vr;
> > +  RANGE_QUERY (cfun)->range_of_expr (vr, var);
> > +  if (vr.undefined_p ())
> > +    vr.set_varying (TREE_TYPE (var));
> > +  *min_value = wi::to_wide (vr.min ());
> > +  *max_value = wi::to_wide (vr.max ());
> > +  value_range_kind vr_type = vr.kind ();
> >     wide_int nonzero = get_nonzero_bits (var);
> >     signop sgn = TYPE_SIGN (TREE_TYPE (var));
> >     if (intersect_range_with_nonzero_bits (vr_type, min_value, max_value,
> > @@ -3437,13 +3444,14 @@ vect_recog_divmod_pattern (vec_info *vinfo,
> >         else
> >       t3 = t2;
> >
> > -      wide_int oprnd0_min, oprnd0_max;
> >         int msb = 1;
> > -      if (get_range_info (oprnd0, &oprnd0_min, &oprnd0_max) == VR_RANGE)
> > +      value_range r;
> > +      RANGE_QUERY (cfun)->range_of_expr (r, oprnd0);
> > +      if (r.kind () == VR_RANGE)
> >       {
> > -       if (!wi::neg_p (oprnd0_min, TYPE_SIGN (itype)))
> > +       if (!wi::neg_p (r.lower_bound (), TYPE_SIGN (itype)))
> >           msb = 0;
> > -       else if (wi::neg_p (oprnd0_max, TYPE_SIGN (itype)))
> > +       else if (wi::neg_p (r.upper_bound (), TYPE_SIGN (itype)))
> >           msb = -1;
> >       }
> >
> > diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
> > index b0f1c47f05c..6a723efc0d8 100644
> > --- a/gcc/tree-vrp.c
> > +++ b/gcc/tree-vrp.c
> > @@ -228,7 +228,7 @@ intersect_range_with_nonzero_bits (enum value_range_kind vr_type,
> >         vr_type = VR_RANGE;
> >       }
> >       }
> > -  if (vr_type == VR_RANGE)
> > +  if (vr_type == VR_RANGE || vr_type == VR_VARYING)
> >       {
> >         *max = wi::round_down_for_mask (*max, nonzero_bits);
> >
> > @@ -1717,7 +1717,7 @@ register_edge_assert_for_2 (tree name, edge e,
> >            simply register the same assert for it.  */
> >         if (CONVERT_EXPR_CODE_P (rhs_code))
> >       {
> > -       wide_int rmin, rmax;
> > +       value_range vr;
> >         tree rhs1 = gimple_assign_rhs1 (def_stmt);
> >         if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
> >             && TREE_CODE (rhs1) == SSA_NAME
> > @@ -1739,13 +1739,14 @@ register_edge_assert_for_2 (tree name, edge e,
> >             && int_fits_type_p (val, TREE_TYPE (rhs1))
> >             && ((TYPE_PRECISION (TREE_TYPE (name))
> >                  > TYPE_PRECISION (TREE_TYPE (rhs1)))
> > -               || (get_range_info (rhs1, &rmin, &rmax) == VR_RANGE
> > +               || ((RANGE_QUERY (cfun)->range_of_expr (vr, rhs1)
> > +                    && vr.kind () == VR_RANGE)
> >                     && wi::fits_to_tree_p
> > -                        (widest_int::from (rmin,
> > +                        (widest_int::from (vr.lower_bound (),
> >                                             TYPE_SIGN (TREE_TYPE (rhs1))),
> >                           TREE_TYPE (name))
> >                     && wi::fits_to_tree_p
> > -                        (widest_int::from (rmax,
> > +                        (widest_int::from (vr.upper_bound (),
> >                                             TYPE_SIGN (TREE_TYPE (rhs1))),
> >                           TREE_TYPE (name)))))
> >           add_assert_info (asserts, rhs1, rhs1,
> > @@ -4631,16 +4632,14 @@ determine_value_range_1 (value_range *vr, tree expr)
> >       vr->set (expr);
> >     else
> >       {
> > -      value_range_kind kind;
> > -      wide_int min, max;
> > +      value_range r;
> >         /* For SSA names try to extract range info computed by VRP.  Otherwise
> >        fall back to varying.  */
> >         if (TREE_CODE (expr) == SSA_NAME
> >         && INTEGRAL_TYPE_P (TREE_TYPE (expr))
> > -       && (kind = get_range_info (expr, &min, &max)) != VR_VARYING)
> > -     vr->set (wide_int_to_tree (TREE_TYPE (expr), min),
> > -              wide_int_to_tree (TREE_TYPE (expr), max),
> > -              kind);
> > +       && RANGE_QUERY (cfun)->range_of_expr (r, expr)
> > +       && !r.undefined_p ())
> > +     *vr = r;
> >         else
> >       vr->set_varying (TREE_TYPE (expr));
> >       }
> > diff --git a/gcc/tree.c b/gcc/tree.c
> > index 31ac4245c9c..3d5111628b5 100644
> > --- a/gcc/tree.c
> > +++ b/gcc/tree.c
> > @@ -68,6 +68,7 @@ along with GCC; see the file COPYING3.  If not see
> >   #include "tree-vector-builder.h"
> >   #include "gimple-fold.h"
> >   #include "escaped_string.h"
> > +#include "gimple-range.h"
> >
> >   /* Tree code classes.  */
> >
> > @@ -13834,8 +13835,8 @@ get_range_pos_neg (tree arg)
> >
> >     if (TREE_CODE (arg) != SSA_NAME)
> >       return 3;
> > -  wide_int arg_min, arg_max;
> > -  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
> > +  value_range r;
> > +  while (!GLOBAL_RANGE_QUERY->range_of_expr (r, arg) || r.kind () != VR_RANGE)
> >       {
> >         gimple *g = SSA_NAME_DEF_STMT (arg);
> >         if (is_gimple_assign (g)
> > @@ -13861,16 +13862,16 @@ get_range_pos_neg (tree arg)
> >       {
> >         /* For unsigned values, the "positive" range comes
> >        below the "negative" range.  */
> > -      if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED))
> > +      if (!wi::neg_p (wi::sext (r.upper_bound (), prec), SIGNED))
> >       return 1;
> > -      if (wi::neg_p (wi::sext (arg_min, prec), SIGNED))
> > +      if (wi::neg_p (wi::sext (r.lower_bound (), prec), SIGNED))
> >       return 2;
> >       }
> >     else
> >       {
> > -      if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED))
> > +      if (!wi::neg_p (wi::sext (r.lower_bound (), prec), SIGNED))
> >       return 1;
> > -      if (wi::neg_p (wi::sext (arg_max, prec), SIGNED))
> > +      if (wi::neg_p (wi::sext (r.upper_bound (), prec), SIGNED))
> >       return 2;
> >       }
> >     return 3;
> > diff --git a/gcc/vr-values.c b/gcc/vr-values.c
> > index a89f0b646ae..02acb46cb20 100644
> > --- a/gcc/vr-values.c
> > +++ b/gcc/vr-values.c
> > @@ -117,14 +117,16 @@ vr_values::get_lattice_entry (const_tree var)
> >            default definitions of PARM_DECLs.  */
> >         if (POINTER_TYPE_P (TREE_TYPE (sym))
> >             && (nonnull_arg_p (sym)
> > -               || get_ptr_nonnull (var)))
> > +               || (GLOBAL_RANGE_QUERY->range_of_expr (*vr,
> > +                                             const_cast <tree> (var))
> > +                   && vr->nonzero_p ())))
> >           {
> >             vr->set_nonzero (TREE_TYPE (sym));
> >             vr->equiv_clear ();
> >           }
> >         else if (INTEGRAL_TYPE_P (TREE_TYPE (sym)))
> >           {
> > -           get_range_info (var, *vr);
> > +           GLOBAL_RANGE_QUERY->range_of_expr (*vr, const_cast <tree> (var));
> >             if (vr->undefined_p ())
> >               vr->set_varying (TREE_TYPE (sym));
> >           }
> > @@ -262,7 +264,7 @@ vr_values::update_value_range (const_tree var, value_range_equiv *new_vr)
> >     if (INTEGRAL_TYPE_P (TREE_TYPE (var)))
> >       {
> >         value_range_equiv nr;
> > -      get_range_info (var, nr);
> > +      GLOBAL_RANGE_QUERY->range_of_expr (nr, const_cast <tree> (var));
> >         if (!nr.undefined_p ())
> >       new_vr->intersect (&nr);
> >       }
> > @@ -3829,13 +3831,13 @@ simplify_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
> >         || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop))
> >       return false;
> >
> > -  /* Get the value-range of the inner operand.  Use get_range_info in
> > +  /* Get the value-range of the inner operand.  Use global ranges in
> >        case innerop was created during substitute-and-fold.  */
> >     wide_int imin, imax;
> >     value_range vr;
> >     if (!INTEGRAL_TYPE_P (TREE_TYPE (innerop)))
> >       return false;
> > -  get_range_info (innerop, vr);
> > +  RANGE_QUERY (cfun)->range_of_expr (vr, innerop, stmt);
> >     if (vr.undefined_p () || vr.varying_p ())
> >       return false;
> >     innermin = widest_int::from (vr.lower_bound (), TYPE_SIGN (TREE_TYPE (innerop)));
> >
>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 4/5] Convert remaining passes to RANGE_QUERY.
  2021-05-24 19:34   ` Martin Sebor
  2021-05-25  8:47     ` Richard Biener
@ 2021-05-25  8:48     ` Aldy Hernandez
  1 sibling, 0 replies; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-25  8:48 UTC (permalink / raw)
  To: Martin Sebor, GCC patches, Andrew MacLeod; +Cc: Martin Sebor



On 5/24/21 9:34 PM, Martin Sebor wrote:
> On 5/21/21 5:39 AM, Aldy Hernandez via Gcc-patches wrote:
>> This patch converts the remaining users of get_range_info and
>> get_ptr_nonnull to the range_query API.
>>
>> No effort was made to move passes away from VR_ANTI_RANGE, or any other
>> use of deprecated methods.  This was a straight up conversion to the new
>> API, nothing else.
> 
> A question about the uses of the RANGE_QUERY() and GLOBAL_RANGE_QUERY()
> macros (hopefully functions): some clients in this patch call one or
> the other based on whether cfun is set or null, while others call it
> without such testing.  That suggests that the former clients might
> be making the assumption that cfun is null while the latter ones
> make the opposite assumption that cfun is not null.  It seems that
> the code would be safer/more future-proof if it avoided making
> these assumptions.

This is by design.

The main ambivalent user is your code in strlen/etc that can be called 
from either builtin expansion or by the sprintf/strlen/etc passes, but 
the common case by far is where cfun is present.  We didn't want to 
penalize the common case by checking.

I actually wanted the user to specifically request a global range (as 
opposed to "whatever is available").  For example, in the legacy 
vr-values code we want to use the global range, also rtl passes, and 
perhaps gimple-pretty-print.c.

Andrew, is that your recolection as well?

Aldy


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] Common API for accessing global and on-demand ranges.
  2021-05-24 16:09 ` [PATCH 1/5] Common API for accessing global and on-demand ranges Aldy Hernandez
@ 2021-05-25  8:57   ` Richard Biener
  2021-05-25  9:36     ` Aldy Hernandez
  0 siblings, 1 reply; 31+ messages in thread
From: Richard Biener @ 2021-05-25  8:57 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: GCC patches, Andrew MacLeod, Martin Sebor

On Mon, May 24, 2021 at 6:44 PM Aldy Hernandez via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
>
>
> On 5/21/21 1:39 PM, Aldy Hernandez wrote:
> > 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:
> >
> >    RANGE_QUERY (cfun)->range_of_expr (vr, name, [stmt]);
>
> BTW, we're not wed to the idea of putting the current range object in
> cfun.  The important thing is that the API is consistent across, not
> where it lives.

If the range object is specific for a function (and thus cannot handle
multiple functions in IPA mode) then struct function looks like the correct
place.  Accessing that unconditionally via 'cfun' sounds bad though because
that disallows use from IPA passes.

>
> We're open to suggestions: a global variable, cfun, the pass manager, or
> even a pass property:
>
>    ( PROP_blah | PROP_ranger ), /* properties_required */
>
> I personally like cfun, but we're open to suggestions.
>
> Aldy
>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 4/5] Convert remaining passes to RANGE_QUERY.
  2021-05-25  8:47     ` Richard Biener
@ 2021-05-25  9:15       ` Aldy Hernandez
  2021-05-25 11:26       ` Aldy Hernandez
  1 sibling, 0 replies; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-25  9:15 UTC (permalink / raw)
  To: Richard Biener, Martin Sebor; +Cc: GCC patches, Andrew MacLeod, Martin Sebor



On 5/25/21 10:47 AM, Richard Biener wrote:
> On Mon, May 24, 2021 at 10:02 PM Martin Sebor via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
>>
>> On 5/21/21 5:39 AM, Aldy Hernandez via Gcc-patches wrote:
>>> This patch converts the remaining users of get_range_info and
>>> get_ptr_nonnull to the range_query API.
>>>
>>> No effort was made to move passes away from VR_ANTI_RANGE, or any other
>>> use of deprecated methods.  This was a straight up conversion to the new
>>> API, nothing else.
>>
>> A question about the uses of the RANGE_QUERY() and GLOBAL_RANGE_QUERY()
>> macros (hopefully functions): some clients in this patch call one or
>> the other based on whether cfun is set or null, while others call it
>> without such testing.  That suggests that the former clients might
>> be making the assumption that cfun is null while the latter ones
>> make the opposite assumption that cfun is not null.  It seems that
>> the code would be safer/more future-proof if it avoided making
>> these assumptions.
>>
>> That could be done by introducing a function like this one:
>>
>>     range_query&
>>     get_range_query (const function *func = cfun)
>>     {
>>       if (func)
>>         return func->x_range_query;
>>       return *get_global_range_query ();
>>     }
>>
>> This function would be easier to use since clients wouldn't have
>> to worry about when cfun is null.
> 
> Note that IPA passes also work on specific 'fun', not 'cfun' and
> that 'cfun' stands in the way of threading GCC.  So please avoid
> adding new references, even more so default args.
> 
> I wonder if SSA_NAME_RANGE_INFO is then obsolete?  What if
> "ranger" is not enabled/available - will this effectively regress things
> by not exposing SSA_NAME_RANGE_INFO (which also encodes
> nonzero bits & friends)?

No, SSA_NAME_RANGE_INFO is not obsolete.  The default range mechanism 
when enable_ranger() has not been called is global_ranges, which is just 
a range_query object that uses SSA_NAME_RANGE_INFO and SSA_NAME_PTR_INFO 
under the covers.  See global_range_query::range_of_expr().

This patchset just provides a generic API so all things range related 
use the same interface.  In the future we may obsolete 
SSA_NAME_RANGE_INFO, but not before we provide all the functionality it 
already provides.  Note that get_nonzero_bits() is currently untouched.

However, what I will remove is global access to get_ptr_nonnull() and 
get_range_info(), since their only remaining user is from the 
range_query object this patchset provides.

Aldy


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] Common API for accessing global and on-demand ranges.
  2021-05-25  8:57   ` Richard Biener
@ 2021-05-25  9:36     ` Aldy Hernandez
  2021-05-25  9:46       ` Richard Biener
  0 siblings, 1 reply; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-25  9:36 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC patches, Andrew MacLeod, Martin Sebor



On 5/25/21 10:57 AM, Richard Biener wrote:
> On Mon, May 24, 2021 at 6:44 PM Aldy Hernandez via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
>>
>>
>>
>> On 5/21/21 1:39 PM, Aldy Hernandez wrote:
>>> 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:
>>>
>>>     RANGE_QUERY (cfun)->range_of_expr (vr, name, [stmt]);
>>
>> BTW, we're not wed to the idea of putting the current range object in
>> cfun.  The important thing is that the API is consistent across, not
>> where it lives.
> 
> If the range object is specific for a function (and thus cannot handle
> multiple functions in IPA mode) then struct function looks like the correct
> place.  Accessing that unconditionally via 'cfun' sounds bad though because
> that disallows use from IPA passes.

The default range object can either be the "global_ranges" object 
(get_range_info / get_ptr_nonnull wrapper) or a ranger.  So, the former 
is global in nature and not tied to any function, and the latter is tied 
to the gimple IL in a function.

What we want is a mechanism from which a pass can query the range of an 
SSA (or expression) at a statement or edge, etc agnostically.  If a 
ranger is activated, use that, otherwise use the global information.

For convenience we wanted a mechanism in which we didn't have to pass an 
object between functions in a pass (be it a ranger or a struct 
function).  Back when I tried to convert some passes to a ranger, it was 
a pain to pass a ranger object around, and having to pass struct 
function would be similarly painful.

ISTM, that most converted passes in this patchset already use cfun 
throughout.  For that matter, even the two IPA ones (ipa-fnsummary and 
ipa-prop) use cfun throughout (by first calling push_cfun (node->decl)).

How about I use fun if easily accessible in a pass, otherwise cfun?  I'm 
trying to avoid having to pass around a struct function in passes that 
require surgery to do so (especially when they're already using cfun).

Basically, we want minimal changes to clients for ease of use.

Aldy


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] Common API for accessing global and on-demand ranges.
  2021-05-25  9:36     ` Aldy Hernandez
@ 2021-05-25  9:46       ` Richard Biener
  2021-05-25 10:53         ` Aldy Hernandez
  0 siblings, 1 reply; 31+ messages in thread
From: Richard Biener @ 2021-05-25  9:46 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: GCC patches, Andrew MacLeod, Martin Sebor

On Tue, May 25, 2021 at 11:36 AM Aldy Hernandez <aldyh@redhat.com> wrote:
>
>
>
> On 5/25/21 10:57 AM, Richard Biener wrote:
> > On Mon, May 24, 2021 at 6:44 PM Aldy Hernandez via Gcc-patches
> > <gcc-patches@gcc.gnu.org> wrote:
> >>
> >>
> >>
> >> On 5/21/21 1:39 PM, Aldy Hernandez wrote:
> >>> 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:
> >>>
> >>>     RANGE_QUERY (cfun)->range_of_expr (vr, name, [stmt]);
> >>
> >> BTW, we're not wed to the idea of putting the current range object in
> >> cfun.  The important thing is that the API is consistent across, not
> >> where it lives.
> >
> > If the range object is specific for a function (and thus cannot handle
> > multiple functions in IPA mode) then struct function looks like the correct
> > place.  Accessing that unconditionally via 'cfun' sounds bad though because
> > that disallows use from IPA passes.
>
> The default range object can either be the "global_ranges" object
> (get_range_info / get_ptr_nonnull wrapper) or a ranger.  So, the former
> is global in nature and not tied to any function, and the latter is tied
> to the gimple IL in a function.
>
> What we want is a mechanism from which a pass can query the range of an
> SSA (or expression) at a statement or edge, etc agnostically.  If a
> ranger is activated, use that, otherwise use the global information.
>
> For convenience we wanted a mechanism in which we didn't have to pass an
> object between functions in a pass (be it a ranger or a struct
> function).  Back when I tried to convert some passes to a ranger, it was
> a pain to pass a ranger object around, and having to pass struct
> function would be similarly painful.
>
> ISTM, that most converted passes in this patchset already use cfun
> throughout.  For that matter, even the two IPA ones (ipa-fnsummary and
> ipa-prop) use cfun throughout (by first calling push_cfun (node->decl)).
>
> How about I use fun if easily accessible in a pass, otherwise cfun?  I'm
> trying to avoid having to pass around a struct function in passes that
> require surgery to do so (especially when they're already using cfun).
>
> Basically, we want minimal changes to clients for ease of use.

I think it's fine to not fix "endusers", esp. if they already use 'cfun'
and fixing would be a lot mechanical work.  What we need to avoid
is implicit uses of cfun via APIs we introduce because that makes
a pass/API that is "cfun" clean, eventually even working on explicit
struct function (and thus IPA safe) no longer so and depend on "cfun"
without that being visible.

The GSoC project to do threading did some cleanups here and
there and in the past we've transitioned to explicit 'cfun' uses
like BASIC_BLOCK_FOR_FN, etc. to expose those and make
pass refactorings meaningful so that a pass using passed around
'cfun' would survive with setting cfun to NULL.

Richard.

> Aldy
>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] Common API for accessing global and on-demand ranges.
  2021-05-25  9:46       ` Richard Biener
@ 2021-05-25 10:53         ` Aldy Hernandez
  2021-05-25 11:06           ` Richard Biener
  0 siblings, 1 reply; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-25 10:53 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC patches, Andrew MacLeod, Martin Sebor

[-- Attachment #1: Type: text/plain, Size: 4030 bytes --]

On 5/25/21 11:46 AM, Richard Biener wrote:
> On Tue, May 25, 2021 at 11:36 AM Aldy Hernandez <aldyh@redhat.com> wrote:
>>
>>
>>
>> On 5/25/21 10:57 AM, Richard Biener wrote:
>>> On Mon, May 24, 2021 at 6:44 PM Aldy Hernandez via Gcc-patches
>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>
>>>>
>>>>
>>>> On 5/21/21 1:39 PM, Aldy Hernandez wrote:
>>>>> 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:
>>>>>
>>>>>      RANGE_QUERY (cfun)->range_of_expr (vr, name, [stmt]);
>>>>
>>>> BTW, we're not wed to the idea of putting the current range object in
>>>> cfun.  The important thing is that the API is consistent across, not
>>>> where it lives.
>>>
>>> If the range object is specific for a function (and thus cannot handle
>>> multiple functions in IPA mode) then struct function looks like the correct
>>> place.  Accessing that unconditionally via 'cfun' sounds bad though because
>>> that disallows use from IPA passes.
>>
>> The default range object can either be the "global_ranges" object
>> (get_range_info / get_ptr_nonnull wrapper) or a ranger.  So, the former
>> is global in nature and not tied to any function, and the latter is tied
>> to the gimple IL in a function.
>>
>> What we want is a mechanism from which a pass can query the range of an
>> SSA (or expression) at a statement or edge, etc agnostically.  If a
>> ranger is activated, use that, otherwise use the global information.
>>
>> For convenience we wanted a mechanism in which we didn't have to pass an
>> object between functions in a pass (be it a ranger or a struct
>> function).  Back when I tried to convert some passes to a ranger, it was
>> a pain to pass a ranger object around, and having to pass struct
>> function would be similarly painful.
>>
>> ISTM, that most converted passes in this patchset already use cfun
>> throughout.  For that matter, even the two IPA ones (ipa-fnsummary and
>> ipa-prop) use cfun throughout (by first calling push_cfun (node->decl)).
>>
>> How about I use fun if easily accessible in a pass, otherwise cfun?  I'm
>> trying to avoid having to pass around a struct function in passes that
>> require surgery to do so (especially when they're already using cfun).
>>
>> Basically, we want minimal changes to clients for ease of use.
> 
> I think it's fine to not fix "endusers", esp. if they already use 'cfun'
> and fixing would be a lot mechanical work.  What we need to avoid
> is implicit uses of cfun via APIs we introduce because that makes
> a pass/API that is "cfun" clean, eventually even working on explicit
> struct function (and thus IPA safe) no longer so and depend on "cfun"
> without that being visible.

Sounds reasonable.

I have removed the use of cfun in get_global_range_query(), so no users 
of GLOBAL_RANGE_QUERY will implicitly use it.

I have verified that all uses of cfun are in passes that already have 
cfun uses, or in the case of -Wrestrict in a pass that requires 
shuffling things around to avoid cfun.  Besides, -Wrestrict is not an 
IPA pass.

Note that there are 3 of uses of the following idiom:

+      if (cfun)
+       RANGE_QUERY (cfun)->range_of_expr (vr, t);
+      else
+       GLOBAL_RANGE_QUERY->range_of_expr (vr, t);

This is for three functions in fold-const.c, gimple-fold.c, and 
tree-dfa.c that may or may not be called with a cfun.  We'd like these 
functions to pick up the current available range object.  But if doing 
so is problematic, I can change it to just use GLOBAL_RANGE_QUERY.

Aldy

[-- Attachment #2: 0001-Common-API-for-accessing-global-and-on-demand-ranges.patch --]
[-- Type: text/x-patch, Size: 15738 bytes --]

From eb294702e7e6a900d521a548cae5a175ea319231 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Wed, 19 May 2021 18:27:05 +0200
Subject: [PATCH 1/6] 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:

  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:

  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 RANGE_QUERY is tied to cfun, 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 cfun, you can use
GLOBAL_RANGE_QUERY instead of RANGE_QUERY(cfun).  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 ? RANGE_QUERY (cfun) : GLOBAL_RANGE_QUERY;

  query->range_of_expr (range, expr, [stmt]);

By default RANGE_QUERY uses 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_RANGE_QUERY.

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.
	(RANGE_QUERY): New.
	(get_global_range_query): New.
	(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            |   4 ++
 gcc/function.h            |  16 +++++
 gcc/gimple-range-cache.cc |   1 -
 gcc/gimple-range.cc       | 127 ++++++++++++++++++++++++++++++++++++++
 gcc/gimple-range.h        |  60 +++++-------------
 gcc/gimple-ssa-evrp.c     |   2 +-
 gcc/tree-vrp.c            |   2 +-
 gcc/value-query.cc        |   5 ++
 gcc/value-query.h         |   1 +
 gcc/vr-values.c           |   2 +-
 gcc/vr-values.h           |   2 +-
 11 files changed, 172 insertions(+), 50 deletions(-)

diff --git a/gcc/function.c b/gcc/function.c
index fc7b147b5f1..67576950983 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -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
diff --git a/gcc/function.h b/gcc/function.h
index 66cfa973808..41b446bfe7c 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -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,14 @@ extern const char *current_function_name (void);
 
 extern void used_types_insert (tree);
 
+extern range_query *get_global_range_query ();
+
+// Returns the currently active range access class.  This is meant to be used
+// with the `class range_query' API.  When there is no active range class,
+// global ranges are used.
+#define RANGE_QUERY(fun) (fun)->x_range_query
+
+// As above, but for accessing global ranges between passes.
+#define GLOBAL_RANGE_QUERY get_global_range_query ()
+
 #endif  /* GCC_FUNCTION_H */
diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 2c922e32913..c645d15f5af 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -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;
 }
 
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 710bc7f9632..a7c1e3b7e69 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -1402,3 +1402,130 @@ 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;
+
+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;
+}
+
+void
+enable_ranger ()
+{
+  gimple_ranger *r;
+
+  if (param_evrp_mode & EVRP_MODE_TRACE)
+    r = new trace_ranger;
+  else
+    r = new gimple_ranger;
+
+  RANGE_QUERY (cfun) = r;
+}
+
+void
+disable_ranger (bool export_ranges)
+{
+  gimple_ranger *r = (gimple_ranger *) RANGE_QUERY (cfun);
+
+  if (export_ranges)
+    r->export_global_ranges ();
+
+  delete r;
+
+  RANGE_QUERY (cfun) = &global_ranges;
+}
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index f33156181bf..1ba073820a6 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -53,7 +53,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;
 protected:
   bool calc_stmt (irange &r, gimple *s, tree name = NULL_TREE);
   bool range_of_range_op (irange &r, gimple *s);
@@ -130,50 +130,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.
 
@@ -202,4 +158,18 @@ private:
 // Temporary external interface to share with vr_values.
 bool range_of_builtin_call (range_query &query, irange &r, gcall *call);
 
+// 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 void enable_ranger ();
+extern void disable_ranger (bool export_ranges = true);
+
 #endif // GCC_GIMPLE_RANGE_STMT_H
diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c
index 5f566ae0958..829fdcdaef2 100644
--- a/gcc/gimple-ssa-evrp.c
+++ b/gcc/gimple-ssa-evrp.c
@@ -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");
       }
   }
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 12e6e6f3e22..b0f1c47f05c 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -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");
     }
 
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 4bb0897c446..509d2d33cc5 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -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>
diff --git a/gcc/value-query.h b/gcc/value-query.h
index e2cbc6852b0..5eff9317ed5 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -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 ();
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index b1bf53af9e0..a89f0b646ae 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -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;
 
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index 8c1b2e0a292..81b9131f7f1 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -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,
-- 
2.31.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] Common API for accessing global and on-demand ranges.
  2021-05-25 10:53         ` Aldy Hernandez
@ 2021-05-25 11:06           ` Richard Biener
  2021-05-25 16:16             ` Aldy Hernandez
  0 siblings, 1 reply; 31+ messages in thread
From: Richard Biener @ 2021-05-25 11:06 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: GCC patches, Andrew MacLeod, Martin Sebor

On Tue, May 25, 2021 at 12:53 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>
> On 5/25/21 11:46 AM, Richard Biener wrote:
> > On Tue, May 25, 2021 at 11:36 AM Aldy Hernandez <aldyh@redhat.com> wrote:
> >>
> >>
> >>
> >> On 5/25/21 10:57 AM, Richard Biener wrote:
> >>> On Mon, May 24, 2021 at 6:44 PM Aldy Hernandez via Gcc-patches
> >>> <gcc-patches@gcc.gnu.org> wrote:
> >>>>
> >>>>
> >>>>
> >>>> On 5/21/21 1:39 PM, Aldy Hernandez wrote:
> >>>>> 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:
> >>>>>
> >>>>>      RANGE_QUERY (cfun)->range_of_expr (vr, name, [stmt]);
> >>>>
> >>>> BTW, we're not wed to the idea of putting the current range object in
> >>>> cfun.  The important thing is that the API is consistent across, not
> >>>> where it lives.
> >>>
> >>> If the range object is specific for a function (and thus cannot handle
> >>> multiple functions in IPA mode) then struct function looks like the correct
> >>> place.  Accessing that unconditionally via 'cfun' sounds bad though because
> >>> that disallows use from IPA passes.
> >>
> >> The default range object can either be the "global_ranges" object
> >> (get_range_info / get_ptr_nonnull wrapper) or a ranger.  So, the former
> >> is global in nature and not tied to any function, and the latter is tied
> >> to the gimple IL in a function.
> >>
> >> What we want is a mechanism from which a pass can query the range of an
> >> SSA (or expression) at a statement or edge, etc agnostically.  If a
> >> ranger is activated, use that, otherwise use the global information.
> >>
> >> For convenience we wanted a mechanism in which we didn't have to pass an
> >> object between functions in a pass (be it a ranger or a struct
> >> function).  Back when I tried to convert some passes to a ranger, it was
> >> a pain to pass a ranger object around, and having to pass struct
> >> function would be similarly painful.
> >>
> >> ISTM, that most converted passes in this patchset already use cfun
> >> throughout.  For that matter, even the two IPA ones (ipa-fnsummary and
> >> ipa-prop) use cfun throughout (by first calling push_cfun (node->decl)).
> >>
> >> How about I use fun if easily accessible in a pass, otherwise cfun?  I'm
> >> trying to avoid having to pass around a struct function in passes that
> >> require surgery to do so (especially when they're already using cfun).
> >>
> >> Basically, we want minimal changes to clients for ease of use.
> >
> > I think it's fine to not fix "endusers", esp. if they already use 'cfun'
> > and fixing would be a lot mechanical work.  What we need to avoid
> > is implicit uses of cfun via APIs we introduce because that makes
> > a pass/API that is "cfun" clean, eventually even working on explicit
> > struct function (and thus IPA safe) no longer so and depend on "cfun"
> > without that being visible.
>
> Sounds reasonable.
>
> I have removed the use of cfun in get_global_range_query(), so no users
> of GLOBAL_RANGE_QUERY will implicitly use it.
>
> I have verified that all uses of cfun are in passes that already have
> cfun uses, or in the case of -Wrestrict in a pass that requires
> shuffling things around to avoid cfun.  Besides, -Wrestrict is not an
> IPA pass.
>
> Note that there are 3 of uses of the following idiom:
>
> +      if (cfun)
> +       RANGE_QUERY (cfun)->range_of_expr (vr, t);
> +      else
> +       GLOBAL_RANGE_QUERY->range_of_expr (vr, t);
>
> This is for three functions in fold-const.c, gimple-fold.c, and
> tree-dfa.c that may or may not be called with a cfun.  We'd like these
> functions to pick up the current available range object.  But if doing
> so is problematic, I can change it to just use GLOBAL_RANGE_QUERY.

I think that's OK for now.  It means that for hypothetical IPA passes
using range queries that they'd get GLOBAL_RANGE_QUERY instead
of the per-function one when running into those functions.

But as you maybe figured there's quite some cfun/current_function_decl
uses in "infrastructure" that has the same issue - we're just trying to reduce
that.

Richard.

> Aldy

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 4/5] Convert remaining passes to RANGE_QUERY.
  2021-05-25  8:47     ` Richard Biener
  2021-05-25  9:15       ` Aldy Hernandez
@ 2021-05-25 11:26       ` Aldy Hernandez
  1 sibling, 0 replies; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-25 11:26 UTC (permalink / raw)
  To: Richard Biener, Martin Sebor; +Cc: GCC patches, Andrew MacLeod, Martin Sebor

[-- Attachment #1: Type: text/plain, Size: 908 bytes --]

Same as before, but with the minor change that the following IPA pass 
uses the correct struct function, as discussed.

Tests on x86-64 Linux on-going.

Aldy

diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index a0238710e72..d8292777647 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -43,6 +43,7 @@
  #include "attribs.h"
  #include "tree-ssa.h"
  #include "tree-cfg.h"
+#include "gimple-range.h"

  /* The idea behind this analyzer is to generate set constraints from the
     program, then solve the resulting constraints in order to generate the
@@ -6740,7 +6741,9 @@ find_what_p_points_to (tree fndecl, tree p)
    struct ptr_info_def *pi;
    tree lookup_p = p;
    varinfo_t vi;
-  bool nonnull = get_ptr_nonnull (p);
+  value_range vr;
+  RANGE_QUERY (DECL_STRUCT_FUNCTION (fndecl))->range_of_expr (vr, p);
+  bool nonnull = vr.nonzero_p ();

[snip]

[-- Attachment #2: 0004-Convert-remaining-passes-to-RANGE_QUERY.patch --]
[-- Type: text/x-patch, Size: 48637 bytes --]

From 2e185f6caab305ac3779097005abf2153c91d1d5 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Wed, 19 May 2021 18:44:08 +0200
Subject: [PATCH 4/5] Convert remaining passes to RANGE_QUERY.

This patch converts the remaining users of get_range_info and
get_ptr_nonnull to the range_query API.

No effort was made to move passes away from VR_ANTI_RANGE, or any other
use of deprecated methods.  This was a straight up conversion to the new
API, nothing else.

gcc/ChangeLog:

	* builtins.c (check_nul_terminated_array): Convert to RANGE_QUERY.
	(expand_builtin_strnlen): Same.
	(determine_block_size): Same.
	* fold-const.c (expr_not_equal_to): Same.
	* gimple-fold.c (size_must_be_zero_p): Same.
	* gimple-match-head.c: Include gimple-range.h.
	* gimple-pretty-print.c (dump_ssaname_info): Convert to RANGE_QUERY.
	* gimple-ssa-warn-restrict.c
	(builtin_memref::extend_offset_range): Same.
	* graphite-sese-to-poly.c (add_param_constraints): Same.
	* internal-fn.c (get_min_precision): Same.
	* ipa-fnsummary.c (set_switch_stmt_execution_predicate): Same.
	* ipa-prop.c (ipa_compute_jump_functions_for_edge): Same.
	* match.pd: Same.
	* tree-data-ref.c (split_constant_offset): Same.
	(dr_step_indicator): Same.
	* tree-dfa.c (get_ref_base_and_extent): Same.
	* tree-scalar-evolution.c (iv_can_overflow_p): Same.
	* tree-ssa-loop-niter.c (refine_value_range_using_guard): Same.
	(determine_value_range): Same.
	(record_nonwrapping_iv): Same.
	(infer_loop_bounds_from_signedness): Same.
	(scev_var_range_cant_overflow): Same.
	* tree-ssa-phiopt.c (two_value_replacement): Same.
	* tree-ssa-pre.c (insert_into_preds_of_block): Same.
	* tree-ssa-reassoc.c (optimize_range_tests_to_bit_test): Same.
	* tree-ssa-strlen.c (handle_builtin_stxncpy_strncat): Same.
	(get_range): Same.
	(dump_strlen_info): Same.
	(set_strlen_range): Same.
	(maybe_diag_stxncpy_trunc): Same.
	(get_len_or_size): Same.
	(handle_integral_assign): Same.
	* tree-ssa-structalias.c (find_what_p_points_to): Same.
	* tree-ssa-uninit.c (find_var_cmp_const): Same.
	* tree-switch-conversion.c (bit_test_cluster::emit): Same.
	* tree-vect-patterns.c (vect_get_range_info): Same.
	(vect_recog_divmod_pattern): Same.
	* tree-vrp.c (intersect_range_with_nonzero_bits): Same.
	(register_edge_assert_for_2): Same.
	(determine_value_range_1): Same.
	* tree.c (get_range_pos_neg): Same.
	* vr-values.c (vr_values::get_lattice_entry): Same.
	(vr_values::update_value_range): Same.
	(simplify_conversion_using_ranges): Same.
---
 gcc/builtins.c                 | 40 ++++++++++------
 gcc/fold-const.c               |  8 +++-
 gcc/gimple-fold.c              |  7 ++-
 gcc/gimple-match-head.c        |  1 +
 gcc/gimple-pretty-print.c      | 12 ++++-
 gcc/gimple-ssa-warn-restrict.c |  8 +++-
 gcc/graphite-sese-to-poly.c    |  9 +++-
 gcc/internal-fn.c              | 14 +++---
 gcc/ipa-fnsummary.c            | 11 ++++-
 gcc/ipa-prop.c                 | 16 +++----
 gcc/match.pd                   | 19 ++++++--
 gcc/tree-data-ref.c            | 24 ++++++++--
 gcc/tree-dfa.c                 | 14 +++++-
 gcc/tree-scalar-evolution.c    | 13 +++++-
 gcc/tree-ssa-loop-niter.c      | 81 +++++++++++++++++++++-----------
 gcc/tree-ssa-phiopt.c          | 11 ++++-
 gcc/tree-ssa-pre.c             | 19 ++++----
 gcc/tree-ssa-reassoc.c         |  9 ++--
 gcc/tree-ssa-strlen.c          | 85 ++++++++++++++++++++--------------
 gcc/tree-ssa-structalias.c     |  8 ++--
 gcc/tree-ssa-uninit.c          |  8 +++-
 gcc/tree-switch-conversion.c   | 10 ++--
 gcc/tree-vect-patterns.c       | 18 +++++--
 gcc/tree-vrp.c                 | 21 ++++-----
 gcc/tree.c                     | 13 +++---
 gcc/vr-values.c                | 12 +++--
 26 files changed, 332 insertions(+), 159 deletions(-)

diff --git a/gcc/builtins.c b/gcc/builtins.c
index e1b284846b1..deb7c083315 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-outof-ssa.h"
 #include "attr-fnspec.h"
 #include "demangle.h"
+#include "gimple-range.h"
 
 struct target_builtins default_target_builtins;
 #if SWITCHABLE_TARGET
@@ -1214,14 +1215,15 @@ check_nul_terminated_array (tree expr, tree src,
   wide_int bndrng[2];
   if (bound)
     {
-      if (TREE_CODE (bound) == INTEGER_CST)
-	bndrng[0] = bndrng[1] = wi::to_wide (bound);
-      else
-	{
-	  value_range_kind rng = get_range_info (bound, bndrng, bndrng + 1);
-	  if (rng != VR_RANGE)
-	    return true;
-	}
+      value_range r;
+
+      GLOBAL_RANGE_QUERY->range_of_expr (r, bound);
+
+      if (r.kind () != VR_RANGE)
+	return true;
+
+      bndrng[0] = r.lower_bound ();
+      bndrng[1] = r.upper_bound ();
 
       if (exact)
 	{
@@ -3827,9 +3829,12 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
     return NULL_RTX;
 
   wide_int min, max;
-  enum value_range_kind rng = get_range_info (bound, &min, &max);
-  if (rng != VR_RANGE)
+  value_range r;
+  GLOBAL_RANGE_QUERY->range_of_expr (r, bound);
+  if (r.kind () != VR_RANGE)
     return NULL_RTX;
+  min = r.lower_bound ();
+  max = r.upper_bound ();
 
   if (!len || TREE_CODE (len) != INTEGER_CST)
     {
@@ -3897,7 +3902,16 @@ determine_block_size (tree len, rtx len_rtx,
 	*probable_max_size = *max_size = GET_MODE_MASK (GET_MODE (len_rtx));
 
       if (TREE_CODE (len) == SSA_NAME)
-	range_type = get_range_info (len, &min, &max);
+	{
+	  value_range r;
+	  GLOBAL_RANGE_QUERY->range_of_expr (r, len);
+	  range_type = r.kind ();
+	  if (range_type != VR_UNDEFINED)
+	    {
+	      min = wi::to_wide (r.min ());
+	      max = wi::to_wide (r.max ());
+	    }
+	}
       if (range_type == VR_RANGE)
 	{
 	  if (wi::fits_uhwi_p (min) && *min_size < min.to_uhwi ())
@@ -4914,8 +4928,8 @@ check_read_access (tree exp, tree src, tree bound /* = NULL_TREE */,
 /* If STMT is a call to an allocation function, returns the constant
    maximum size of the object allocated by the call represented as
    sizetype.  If nonnull, sets RNG1[] to the range of the size.
-   When nonnull, uses RVALS for range information, otherwise calls
-   get_range_info to get it.
+   When nonnull, uses RVALS for range information, otherwise gets global
+   range info.
    Returns null when STMT is not a call to a valid allocation function.  */
 
 tree
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 5a41524702b..d680ba1442f 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -83,6 +83,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vector-builder.h"
 #include "vec-perm-indices.h"
 #include "asan.h"
+#include "gimple-range.h"
 
 /* Nonzero if we are folding constants inside an initializer; zero
    otherwise.  */
@@ -10686,7 +10687,12 @@ expr_not_equal_to (tree t, const wide_int &w)
     case SSA_NAME:
       if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
 	return false;
-      get_range_info (t, vr);
+
+      if (cfun)
+	RANGE_QUERY (cfun)->range_of_expr (vr, t);
+      else
+	GLOBAL_RANGE_QUERY->range_of_expr (vr, t);
+
       if (!vr.undefined_p ()
 	  && !vr.contains_p (wide_int_to_tree (TREE_TYPE (t), w)))
 	return true;
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 68717cf1542..228fa1b357f 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -873,7 +873,12 @@ size_must_be_zero_p (tree size)
   value_range valid_range (build_int_cst (type, 0),
 			   wide_int_to_tree (type, ssize_max));
   value_range vr;
-  get_range_info (size, vr);
+  if (cfun)
+    RANGE_QUERY (cfun)->range_of_expr (vr, size);
+  else
+    GLOBAL_RANGE_QUERY->range_of_expr (vr, size);
+  if (vr.undefined_p ())
+    vr.set_varying (TREE_TYPE (size));
   vr.intersect (&valid_range);
   return vr.zero_p ();
 }
diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c
index b084a31572a..7112c116835 100644
--- a/gcc/gimple-match-head.c
+++ b/gcc/gimple-match-head.c
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-eh.h"
 #include "dbgcnt.h"
 #include "tm.h"
+#include "gimple-range.h"
 
 /* Forward declarations of the private auto-generated matchers.
    They expect valueized operands in canonical order and do not
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 0ef01e6420b..62d895d1625 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "asan.h"
 #include "cfgloop.h"
+#include "gimple-range.h"
 
 /* Disable warnings about quoting issues in the pp_xxx calls below
    that (intentionally) don't follow GCC diagnostic conventions.  */
@@ -2263,8 +2264,17 @@ dump_ssaname_info (pretty_printer *buffer, tree node, int spc)
       && SSA_NAME_RANGE_INFO (node))
     {
       wide_int min, max, nonzero_bits;
-      value_range_kind range_type = get_range_info (node, &min, &max);
+      value_range r;
 
+      GLOBAL_RANGE_QUERY->range_of_expr (r, node);
+      value_range_kind range_type = r.kind ();
+      if (!r.undefined_p ())
+	{
+	  min = wi::to_wide (r.min ());
+	  max = wi::to_wide (r.max ());
+	}
+
+      // FIXME: Use irange::dump() instead.
       if (range_type == VR_VARYING)
 	pp_printf (buffer, "# RANGE VR_VARYING");
       else if (range_type == VR_RANGE || range_type == VR_ANTI_RANGE)
diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
index ad37f20afaa..a59731c2bc2 100644
--- a/gcc/gimple-ssa-warn-restrict.c
+++ b/gcc/gimple-ssa-warn-restrict.c
@@ -349,7 +349,13 @@ builtin_memref::extend_offset_range (tree offset)
 	  /* There is a global version here because
 	     check_bounds_or_overlap may be called from gimple
 	     fold during gimple lowering.  */
-	  rng = get_range_info (offset, &min, &max);
+	  RANGE_QUERY (cfun)->range_of_expr (vr, offset, stmt);
+	  rng = vr.kind ();
+	  if (!vr.undefined_p ())
+	    {
+	      min = wi::to_wide (vr.min ());
+	      max = wi::to_wide (vr.max ());
+	    }
 	}
       if (rng == VR_ANTI_RANGE && wi::lts_p (max, min))
 	{
diff --git a/gcc/graphite-sese-to-poly.c b/gcc/graphite-sese-to-poly.c
index eebf2e02cfc..2d332f69a92 100644
--- a/gcc/graphite-sese-to-poly.c
+++ b/gcc/graphite-sese-to-poly.c
@@ -418,13 +418,18 @@ static void
 add_param_constraints (scop_p scop, graphite_dim_t p, tree parameter)
 {
   tree type = TREE_TYPE (parameter);
+  value_range r;
   wide_int min, max;
 
   gcc_assert (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type));
 
   if (INTEGRAL_TYPE_P (type)
-      && get_range_info (parameter, &min, &max) == VR_RANGE)
-    ;
+      && RANGE_QUERY (cfun)->range_of_expr (r, parameter)
+      && !r.undefined_p ())
+    {
+      min = r.lower_bound ();
+      max = r.upper_bound ();
+    }
   else
     {
       min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index d209a52f823..dd1f204863e 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ssa-iterators.h"
 #include "explow.h"
 #include "rtl-iter.h"
+#include "gimple-range.h"
 
 /* The names of each internal function, indexed by function number.  */
 const char *const internal_fn_name_array[] = {
@@ -680,8 +681,9 @@ get_min_precision (tree arg, signop sign)
     }
   if (TREE_CODE (arg) != SSA_NAME)
     return prec + (orig_sign != sign);
-  wide_int arg_min, arg_max;
-  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
+  value_range r;
+  while (!GLOBAL_RANGE_QUERY->range_of_expr (r, arg)
+	 || r.kind () != VR_RANGE)
     {
       gimple *g = SSA_NAME_DEF_STMT (arg);
       if (is_gimple_assign (g)
@@ -709,14 +711,14 @@ get_min_precision (tree arg, signop sign)
     }
   if (sign == TYPE_SIGN (TREE_TYPE (arg)))
     {
-      int p1 = wi::min_precision (arg_min, sign);
-      int p2 = wi::min_precision (arg_max, sign);
+      int p1 = wi::min_precision (r.lower_bound (), sign);
+      int p2 = wi::min_precision (r.upper_bound (), sign);
       p1 = MAX (p1, p2);
       prec = MIN (prec, p1);
     }
-  else if (sign == UNSIGNED && !wi::neg_p (arg_min, SIGNED))
+  else if (sign == UNSIGNED && !wi::neg_p (r.lower_bound (), SIGNED))
     {
-      int p = wi::min_precision (arg_max, UNSIGNED);
+      int p = wi::min_precision (r.upper_bound (), UNSIGNED);
       prec = MIN (prec, p);
     }
   return prec + (orig_sign != sign);
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 4e5be812734..299d7fc1f60 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -85,6 +85,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "tree-into-ssa.h"
 #include "symtab-clones.h"
+#include "gimple-range.h"
 
 /* Summaries.  */
 fast_function_summary <ipa_fn_summary *, va_gc> *ipa_fn_summaries;
@@ -1687,8 +1688,14 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
   int bound_limit = opt_for_fn (fbi->node->decl,
 				param_ipa_max_switch_predicate_bounds);
   int bound_count = 0;
-  wide_int vr_wmin, vr_wmax;
-  value_range_kind vr_type = get_range_info (op, &vr_wmin, &vr_wmax);
+  value_range vr;
+
+  RANGE_QUERY (cfun)->range_of_expr (vr, op);
+  if (vr.undefined_p ())
+    vr.set_varying (TREE_TYPE (op));
+  value_range_kind vr_type = vr.kind ();
+  wide_int vr_wmin = wi::to_wide (vr.min ());
+  wide_int vr_wmax = wi::to_wide (vr.max ());
 
   FOR_EACH_EDGE (e, ei, bb->succs)
     {
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 0591ef1b569..02f422bdbf3 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -55,6 +55,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "options.h"
 #include "symtab-clones.h"
 #include "attr-fnspec.h"
+#include "gimple-range.h"
 
 /* Function summary where the parameter infos are actually stored. */
 ipa_node_params_t *ipa_node_params_sum = NULL;
@@ -2237,6 +2238,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
   gcall *call = cs->call_stmt;
   int n, arg_num = gimple_call_num_args (call);
   bool useful_context = false;
+  value_range vr;
 
   if (arg_num == 0 || args->jump_functions)
     return;
@@ -2274,7 +2276,8 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 
 	  if (TREE_CODE (arg) == SSA_NAME
 	      && param_type
-	      && get_ptr_nonnull (arg))
+	      && RANGE_QUERY (cfun)->range_of_expr (vr, arg)
+	      && vr.nonzero_p ())
 	    addr_nonzero = true;
 	  else if (tree_single_nonzero_warnv_p (arg, &strict_overflow))
 	    addr_nonzero = true;
@@ -2289,19 +2292,14 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	}
       else
 	{
-	  wide_int min, max;
-	  value_range_kind kind;
 	  if (TREE_CODE (arg) == SSA_NAME
 	      && param_type
-	      && (kind = get_range_info (arg, &min, &max))
-	      && (kind == VR_RANGE || kind == VR_ANTI_RANGE))
+	      && RANGE_QUERY (cfun)->range_of_expr (vr, arg)
+	      && !vr.undefined_p ())
 	    {
 	      value_range resvr;
-	      value_range tmpvr (wide_int_to_tree (TREE_TYPE (arg), min),
-				 wide_int_to_tree (TREE_TYPE (arg), max),
-				 kind);
 	      range_fold_unary_expr (&resvr, NOP_EXPR, param_type,
-				     &tmpvr, TREE_TYPE (arg));
+				     &vr, TREE_TYPE (arg));
 	      if (!resvr.undefined_p () && !resvr.varying_p ())
 		ipa_set_jfunc_vr (jfunc, &resvr);
 	      else
diff --git a/gcc/match.pd b/gcc/match.pd
index cdb87636951..9dddf5ebd0a 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -663,11 +663,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (with
      {
        bool overflowed = true;
-       wide_int wmin0, wmax0, wmin1, wmax1;
+       value_range vr0, vr1;
        if (INTEGRAL_TYPE_P (type)
-	   && get_range_info (@0, &wmin0, &wmax0) == VR_RANGE
-	   && get_range_info (@1, &wmin1, &wmax1) == VR_RANGE)
+	   && GLOBAL_RANGE_QUERY->range_of_expr (vr0, @0)
+	   && GLOBAL_RANGE_QUERY->range_of_expr (vr1, @1)
+	   && vr0.kind () == VR_RANGE
+	   && vr1.kind () == VR_RANGE)
 	 {
+	   wide_int wmin0 = vr0.lower_bound ();
+	   wide_int wmax0 = vr0.upper_bound ();
+	   wide_int wmin1 = vr1.lower_bound ();
+	   wide_int wmax1 = vr1.upper_bound ();
 	   /* If the multiplication can't overflow/wrap around, then
 	      it can be optimized too.  */
 	   wi::overflow_type min_ovf, max_ovf;
@@ -2509,9 +2515,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 	  = wide_int::from (wi::to_wide (@1), TYPE_PRECISION (inner_type),
 			    TYPE_SIGN (inner_type));
 
-        wide_int wmin0, wmax0;
-        if (get_range_info (@0, &wmin0, &wmax0) == VR_RANGE)
+	value_range vr;
+	if (GLOBAL_RANGE_QUERY->range_of_expr (vr, @0)
+	    && vr.kind () == VR_RANGE)
           {
+	    wide_int wmin0 = vr.lower_bound ();
+	    wide_int wmax0 = vr.upper_bound ();
             wi::add (wmin0, w1, TYPE_SIGN (inner_type), &min_ovf);
             wi::add (wmax0, w1, TYPE_SIGN (inner_type), &max_ovf);
           }
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index e6dd5f15bed..5ba41e2c73d 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -1035,14 +1035,23 @@ split_constant_offset (tree exp, tree *var, tree *off, value_range *exp_range,
       *exp_range = type;
       if (code == SSA_NAME)
 	{
-	  wide_int var_min, var_max;
-	  value_range_kind vr_kind = get_range_info (exp, &var_min, &var_max);
+	  value_range vr;
+	  RANGE_QUERY (cfun)->range_of_expr (vr, exp);
+	  if (vr.undefined_p ())
+	    vr.set_varying (TREE_TYPE (exp));
+	  wide_int var_min = wi::to_wide (vr.min ());
+	  wide_int var_max = wi::to_wide (vr.max ());
+	  value_range_kind vr_kind = vr.kind ();
 	  wide_int var_nonzero = get_nonzero_bits (exp);
 	  vr_kind = intersect_range_with_nonzero_bits (vr_kind,
 						       &var_min, &var_max,
 						       var_nonzero,
 						       TYPE_SIGN (type));
-	  if (vr_kind == VR_RANGE)
+	  /* This check for VR_VARYING is here because the old code
+	     using get_range_info would return VR_RANGE for the entire
+	     domain, instead of VR_VARYING.  The new code normalizes
+	     full-domain ranges to VR_VARYING.  */
+	  if (vr_kind == VR_RANGE || vr_kind == VR_VARYING)
 	    *exp_range = value_range (type, var_min, var_max);
 	}
     }
@@ -6298,12 +6307,19 @@ dr_step_indicator (struct data_reference *dr, int useful_min)
 
       /* Get the range of values that the unconverted step actually has.  */
       wide_int step_min, step_max;
+      value_range vr;
       if (TREE_CODE (step) != SSA_NAME
-	  || get_range_info (step, &step_min, &step_max) != VR_RANGE)
+	  || !RANGE_QUERY (cfun)->range_of_expr (vr, step)
+	  || vr.kind () != VR_RANGE)
 	{
 	  step_min = wi::to_wide (TYPE_MIN_VALUE (type));
 	  step_max = wi::to_wide (TYPE_MAX_VALUE (type));
 	}
+      else
+	{
+	  step_min = vr.lower_bound ();
+	  step_max = vr.upper_bound ();
+	}
 
       /* Check whether the unconverted step has an acceptable range.  */
       signop sgn = TYPE_SIGN (type);
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 0482b05e26c..e9cf4bfa706 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-iterator.h"
 #include "gimple-walk.h"
 #include "tree-dfa.h"
+#include "gimple-range.h"
 
 /* Build and maintain data flow information for trees.  */
 
@@ -530,14 +531,23 @@ get_ref_base_and_extent (tree exp, poly_int64_pod *poffset,
 		   index.  */
 		seen_variable_array_ref = true;
 
-		wide_int min, max;
+		value_range vr;
+		range_query *query;
+		if (cfun)
+		  query = RANGE_QUERY (cfun);
+		else
+		  query = GLOBAL_RANGE_QUERY;
+
 		if (TREE_CODE (index) == SSA_NAME
 		    && (low_bound = array_ref_low_bound (exp),
 			poly_int_tree_p (low_bound))
 		    && (unit_size = array_ref_element_size (exp),
 			TREE_CODE (unit_size) == INTEGER_CST)
-		    && get_range_info (index, &min, &max) == VR_RANGE)
+		    && query->range_of_expr (vr, index)
+		    && vr.kind () == VR_RANGE)
 		  {
+		    wide_int min = vr.lower_bound ();
+		    wide_int max = vr.upper_bound ();
 		    poly_offset_int lbound = wi::to_poly_offset (low_bound);
 		    /* Try to constrain maxsize with range information.  */
 		    offset_int omax
diff --git a/gcc/tree-scalar-evolution.c b/gcc/tree-scalar-evolution.c
index ff052be1021..f0f28f26042 100644
--- a/gcc/tree-scalar-evolution.c
+++ b/gcc/tree-scalar-evolution.c
@@ -3039,18 +3039,27 @@ iv_can_overflow_p (class loop *loop, tree type, tree base, tree step)
   widest_int nit;
   wide_int base_min, base_max, step_min, step_max, type_min, type_max;
   signop sgn = TYPE_SIGN (type);
+  value_range r;
 
   if (integer_zerop (step))
     return false;
 
   if (!INTEGRAL_TYPE_P (TREE_TYPE (base))
-      || get_range_info (base, &base_min, &base_max) != VR_RANGE)
+      || !RANGE_QUERY (cfun)->range_of_expr (r, base)
+      || r.kind () != VR_RANGE)
     return true;
 
+  base_min = r.lower_bound ();
+  base_max = r.upper_bound ();
+
   if (!INTEGRAL_TYPE_P (TREE_TYPE (step))
-      || get_range_info (step, &step_min, &step_max) != VR_RANGE)
+      || !RANGE_QUERY (cfun)->range_of_expr (r, step)
+      || r.kind () != VR_RANGE)
     return true;
 
+  step_min = r.lower_bound ();
+  step_max = r.upper_bound ();
+
   if (!get_max_loop_iterations (loop, &nit))
     return true;
 
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 3817ec423e7..bfbb11c59c5 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-chrec.h"
 #include "tree-scalar-evolution.h"
 #include "tree-dfa.h"
+#include "gimple-range.h"
 
 
 /* The maximum number of dominator BBs we search for conditions
@@ -121,7 +122,6 @@ refine_value_range_using_guard (tree type, tree var,
   tree varc0, varc1, ctype;
   mpz_t offc0, offc1;
   mpz_t mint, maxt, minc1, maxc1;
-  wide_int minv, maxv;
   bool no_wrap = nowrap_type_p (type);
   bool c0_ok, c1_ok;
   signop sgn = TYPE_SIGN (type);
@@ -221,6 +221,7 @@ refine_value_range_using_guard (tree type, tree var,
   get_type_static_bounds (type, mint, maxt);
   mpz_init (minc1);
   mpz_init (maxc1);
+  value_range r;
   /* Setup range information for varc1.  */
   if (integer_zerop (varc1))
     {
@@ -229,11 +230,12 @@ refine_value_range_using_guard (tree type, tree var,
     }
   else if (TREE_CODE (varc1) == SSA_NAME
 	   && INTEGRAL_TYPE_P (type)
-	   && get_range_info (varc1, &minv, &maxv) == VR_RANGE)
+	   && RANGE_QUERY (cfun)->range_of_expr (r, varc1)
+	   && r.kind () == VR_RANGE)
     {
-      gcc_assert (wi::le_p (minv, maxv, sgn));
-      wi::to_mpz (minv, minc1, sgn);
-      wi::to_mpz (maxv, maxc1, sgn);
+      gcc_assert (wi::le_p (r.lower_bound (), r.upper_bound (), sgn));
+      wi::to_mpz (r.lower_bound (), minc1, sgn);
+      wi::to_mpz (r.upper_bound (), maxc1, sgn);
     }
   else
     {
@@ -372,34 +374,50 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
       gphi_iterator gsi;
 
       /* Either for VAR itself...  */
-      rtype = get_range_info (var, &minv, &maxv);
+      value_range var_range;
+      RANGE_QUERY (cfun)->range_of_expr (var_range, var);
+      rtype = var_range.kind ();
+      if (!var_range.undefined_p ())
+	{
+	  minv = var_range.lower_bound ();
+	  maxv = var_range.upper_bound ();
+	}
+
       /* Or for PHI results in loop->header where VAR is used as
 	 PHI argument from the loop preheader edge.  */
       for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi))
 	{
 	  gphi *phi = gsi.phi ();
-	  wide_int minc, maxc;
+	  value_range phi_range;
 	  if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var
-	      && (get_range_info (gimple_phi_result (phi), &minc, &maxc)
-		  == VR_RANGE))
+	      && RANGE_QUERY (cfun)->range_of_expr (phi_range,
+						    gimple_phi_result (phi))
+	      && phi_range.kind () == VR_RANGE)
 	    {
 	      if (rtype != VR_RANGE)
 		{
 		  rtype = VR_RANGE;
-		  minv = minc;
-		  maxv = maxc;
+		  minv = phi_range.lower_bound ();
+		  maxv = phi_range.upper_bound ();
 		}
 	      else
 		{
-		  minv = wi::max (minv, minc, sgn);
-		  maxv = wi::min (maxv, maxc, sgn);
+		  minv = wi::max (minv, phi_range.lower_bound (), sgn);
+		  maxv = wi::min (maxv, phi_range.upper_bound (), sgn);
 		  /* If the PHI result range are inconsistent with
 		     the VAR range, give up on looking at the PHI
 		     results.  This can happen if VR_UNDEFINED is
 		     involved.  */
 		  if (wi::gt_p (minv, maxv, sgn))
 		    {
-		      rtype = get_range_info (var, &minv, &maxv);
+		      value_range vr;
+		      RANGE_QUERY (cfun)->range_of_expr (vr, var);
+		      rtype = vr.kind ();
+		      if (!vr.undefined_p ())
+			{
+			  minv = vr.lower_bound ();
+			  maxv = vr.upper_bound ();
+			}
 		      break;
 		    }
 		}
@@ -3545,12 +3563,16 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
 
   if (tree_int_cst_sign_bit (step))
     {
-      wide_int min, max;
+      wide_int max;
+      value_range base_range;
+      if (RANGE_QUERY (cfun)->range_of_expr (base_range, orig_base)
+	  && !base_range.undefined_p ())
+	max = base_range.upper_bound ();
       extreme = fold_convert (unsigned_type, low);
       if (TREE_CODE (orig_base) == SSA_NAME
 	  && TREE_CODE (high) == INTEGER_CST
 	  && INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
-	  && (get_range_info (orig_base, &min, &max) == VR_RANGE
+	  && (base_range.kind () == VR_RANGE
 	      || get_cst_init_from_scev (orig_base, &max, false))
 	  && wi::gts_p (wi::to_wide (high), max))
 	base = wide_int_to_tree (unsigned_type, max);
@@ -3563,12 +3585,16 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
     }
   else
     {
-      wide_int min, max;
+      wide_int min;
+      value_range base_range;
+      if (RANGE_QUERY (cfun)->range_of_expr (base_range, orig_base)
+	  && !base_range.undefined_p ())
+	min = base_range.lower_bound ();
       extreme = fold_convert (unsigned_type, high);
       if (TREE_CODE (orig_base) == SSA_NAME
 	  && TREE_CODE (low) == INTEGER_CST
 	  && INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
-	  && (get_range_info (orig_base, &min, &max) == VR_RANGE
+	  && (base_range.kind () == VR_RANGE
 	      || get_cst_init_from_scev (orig_base, &min, true))
 	  && wi::gts_p (min, wi::to_wide (low)))
 	base = wide_int_to_tree (unsigned_type, min);
@@ -3835,11 +3861,12 @@ infer_loop_bounds_from_signedness (class loop *loop, gimple *stmt)
 
   low = lower_bound_in_type (type, type);
   high = upper_bound_in_type (type, type);
-  wide_int minv, maxv;
-  if (get_range_info (def, &minv, &maxv) == VR_RANGE)
+  value_range r;
+  RANGE_QUERY (cfun)->range_of_expr (r, def);
+  if (r.kind () == VR_RANGE)
     {
-      low = wide_int_to_tree (type, minv);
-      high = wide_int_to_tree (type, maxv);
+      low = wide_int_to_tree (type, r.lower_bound ());
+      high = wide_int_to_tree (type, r.upper_bound ());
     }
 
   record_nonwrapping_iv (loop, base, step, stmt, low, high, false, true);
@@ -4873,7 +4900,6 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
 {
   tree type;
   wide_int minv, maxv, diff, step_wi;
-  enum value_range_kind rtype;
 
   if (TREE_CODE (step) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (var)))
     return false;
@@ -4884,8 +4910,9 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
   if (!def_bb || !dominated_by_p (CDI_DOMINATORS, loop->latch, def_bb))
     return false;
 
-  rtype = get_range_info (var, &minv, &maxv);
-  if (rtype != VR_RANGE)
+  value_range r;
+  RANGE_QUERY (cfun)->range_of_expr (r, var);
+  if (r.kind () != VR_RANGE)
     return false;
 
   /* VAR is a scev whose evolution part is STEP and value range info
@@ -4899,11 +4926,11 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
   type = TREE_TYPE (var);
   if (tree_int_cst_sign_bit (step))
     {
-      diff = minv - wi::to_wide (lower_bound_in_type (type, type));
+      diff = r.lower_bound () - wi::to_wide (lower_bound_in_type (type, type));
       step_wi = - step_wi;
     }
   else
-    diff = wi::to_wide (upper_bound_in_type (type, type)) - maxv;
+    diff = wi::to_wide (upper_bound_in_type (type, type)) - r.upper_bound ();
 
   return (wi::geu_p (diff, step_wi));
 }
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
index 8e8a08bc679..d464c84f164 100644
--- a/gcc/tree-ssa-phiopt.c
+++ b/gcc/tree-ssa-phiopt.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-eh.h"
 #include "gimple-fold.h"
 #include "internal-fn.h"
+#include "gimple-range.h"
 
 static unsigned int tree_ssa_phiopt_worker (bool, bool, bool);
 static bool two_value_replacement (basic_block, basic_block, edge, gphi *,
@@ -684,7 +685,15 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb,
     return false;
 
   wide_int min, max;
-  if (get_range_info (lhs, &min, &max) != VR_RANGE)
+  value_range r;
+  RANGE_QUERY (cfun)->range_of_expr (r, lhs);
+
+  if (r.kind () == VR_RANGE)
+    {
+      min = r.lower_bound ();
+      max = r.upper_bound ();
+    }
+  else
     {
       int prec = TYPE_PRECISION (TREE_TYPE (lhs));
       signop sgn = TYPE_SIGN (TREE_TYPE (lhs));
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index 2d22535af87..870d3cba9ff 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-dce.h"
 #include "tree-cfgcleanup.h"
 #include "alias.h"
+#include "gimple-range.h"
 
 /* Even though this file is called tree-ssa-pre.c, we actually
    implement a bit more than just PRE here.  All of them piggy-back
@@ -3234,16 +3235,18 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
 	  >= TYPE_PRECISION (TREE_TYPE (expr->u.nary->op[0])))
       && SSA_NAME_RANGE_INFO (expr->u.nary->op[0]))
     {
-      wide_int min, max;
-      if (get_range_info (expr->u.nary->op[0], &min, &max) == VR_RANGE
-	  && !wi::neg_p (min, SIGNED)
-	  && !wi::neg_p (max, SIGNED))
+      value_range r;
+      if (RANGE_QUERY (cfun)->range_of_expr (r, expr->u.nary->op[0])
+	  && r.kind () == VR_RANGE
+	  && !wi::neg_p (r.lower_bound (), SIGNED)
+	  && !wi::neg_p (r.upper_bound (), SIGNED))
 	/* Just handle extension and sign-changes of all-positive ranges.  */
-	set_range_info (temp,
-			SSA_NAME_RANGE_TYPE (expr->u.nary->op[0]),
-			wide_int_storage::from (min, TYPE_PRECISION (type),
+	set_range_info (temp, VR_RANGE,
+			wide_int_storage::from (r.lower_bound (),
+						TYPE_PRECISION (type),
 						TYPE_SIGN (type)),
-			wide_int_storage::from (max, TYPE_PRECISION (type),
+			wide_int_storage::from (r.upper_bound (),
+						TYPE_PRECISION (type),
 						TYPE_SIGN (type)));
     }
 
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 32e1632705b..cc098369e2e 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "tree-ssa-reassoc.h"
 #include "tree-ssa-math-opts.h"
+#include "gimple-range.h"
 
 /*  This is a simple global reassociation pass.  It is, in part, based
     on the LLVM pass of the same name (They do some things more/less
@@ -3221,12 +3222,14 @@ optimize_range_tests_to_bit_test (enum tree_code opcode, int first, int length,
 	 amount, then we can merge the entry test in the bit test.  In this
 	 case, if we would need otherwise 2 or more comparisons, then use
 	 the bit test; in the other cases, the threshold is 3 comparisons.  */
-      wide_int min, max;
       bool entry_test_needed;
+      value_range r;
       if (TREE_CODE (exp) == SSA_NAME
-	  && get_range_info (exp, &min, &max) == VR_RANGE
-	  && wi::leu_p (max - min, prec - 1))
+	  && RANGE_QUERY (cfun)->range_of_expr (r, exp)
+	  && r.kind () == VR_RANGE
+	  && wi::leu_p (r.upper_bound () - r.lower_bound (), prec - 1))
 	{
+	  wide_int min = r.lower_bound ();
 	  wide_int ilowi = wi::to_wide (lowi);
 	  if (wi::lt_p (min, ilowi, TYPE_SIGN (TREE_TYPE (lowi))))
 	    {
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index c7b5e2c6e6b..2f85a609107 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -196,7 +196,7 @@ static void handle_builtin_stxncpy_strncat (bool, gimple_stmt_iterator *);
 /* Sets MINMAX to either the constant value or the range VAL is in
    and returns either the constant value or VAL on success or null
    when the range couldn't be determined.  Uses RVALS when nonnull
-   to determine the range, otherwise get_range_info.  */
+   to determine the range, otherwise uses global range info.  */
 
 tree
 get_range (tree val, gimple *stmt, wide_int minmax[2],
@@ -211,9 +211,9 @@ get_range (tree val, gimple *stmt, wide_int minmax[2],
   if (TREE_CODE (val) != SSA_NAME)
     return NULL_TREE;
 
+  value_range vr;
   if (rvals && stmt)
     {
-      value_range vr;
       if (!rvals->range_of_expr (vr, val, stmt))
 	return NULL_TREE;
       value_range_kind rng = vr.kind ();
@@ -225,7 +225,15 @@ get_range (tree val, gimple *stmt, wide_int minmax[2],
       return val;
     }
 
-  value_range_kind rng = get_range_info (val, minmax, minmax + 1);
+  // ?? This entire function should use RANGE_QUERY or GLOBAL_RANGE_QUERY,
+  // instead of doing something different for RVALS and global ranges.
+
+  if (!GLOBAL_RANGE_QUERY->range_of_expr (vr, val) || vr.undefined_p ())
+    return NULL_TREE;
+
+  minmax[0] = wi::to_wide (vr.min ());
+  minmax[1] = wi::to_wide (vr.max ());
+  value_range_kind rng = vr.kind ();
   if (rng == VR_RANGE)
     /* This may be an inverted range whose MINMAX[1] < MINMAX[0].  */
     return val;
@@ -929,7 +937,17 @@ dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals)
 			    rng = VR_UNDEFINED;
 			}
 		      else
-			rng = get_range_info (si->nonzero_chars, &min, &max);
+			{
+			  value_range vr;
+			  GLOBAL_RANGE_QUERY->range_of_expr (vr,
+							     si->nonzero_chars);
+			  rng = vr.kind ();
+			  if (!vr.undefined_p ())
+			    {
+			      min = wi::to_wide (vr.min ());
+			      max = wi::to_wide (vr.max ());
+			    }
+			}
 
 		      if (rng == VR_RANGE || rng == VR_ANTI_RANGE)
 			{
@@ -1809,18 +1827,17 @@ set_strlen_range (tree lhs, wide_int min, wide_int max,
 	}
       else if (TREE_CODE (bound) == SSA_NAME)
 	{
-	  wide_int minbound, maxbound;
-	  // FIXME: Use range_query instead of global ranges.
-	  value_range_kind rng = get_range_info (bound, &minbound, &maxbound);
-	  if (rng == VR_RANGE)
+	  value_range r;
+	  RANGE_QUERY (cfun)->range_of_expr (r, bound);
+	  if (!r.undefined_p ())
 	    {
 	      /* For a bound in a known range, adjust the range determined
 		 above as necessary.  For a bound in some anti-range or
 		 in an unknown range, use the range determined by callers.  */
-	      if (wi::ltu_p (minbound, min))
-		min = minbound;
-	      if (wi::ltu_p (maxbound, max))
-		max = maxbound;
+	      if (wi::ltu_p (r.lower_bound (), min))
+		min = r.lower_bound ();
+	      if (wi::ltu_p (r.upper_bound (), max))
+		max = r.upper_bound ();
 	    }
 	}
     }
@@ -2780,12 +2797,15 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt,
     return false;
 
   wide_int cntrange[2];
+  value_range r;
+  if (!RANGE_QUERY (cfun)->range_of_expr (r, cnt)
+      || r.varying_p ()
+      || r.undefined_p ())
+    return false;
 
-  // FIXME: Use range_query instead of global ranges.
-  enum value_range_kind rng = get_range_info (cnt, cntrange, cntrange + 1);
-  if (rng == VR_RANGE)
-    ;
-  else if (rng == VR_ANTI_RANGE)
+  cntrange[0] = wi::to_wide (r.min ());
+  cntrange[1] = wi::to_wide (r.max ());
+  if (r.kind () == VR_ANTI_RANGE)
     {
       wide_int maxobjsize = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
 
@@ -2800,8 +2820,6 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt,
 	  cntrange[0] = wi::zero (TYPE_PRECISION (TREE_TYPE (cnt)));
 	}
     }
-  else
-    return false;
 
   /* Negative value is the constant string length.  If it's less than
      the lower bound there is no truncation.  Avoid calling get_stridx()
@@ -3923,13 +3941,12 @@ get_len_or_size (gimple *stmt, tree arg, int idx,
 	}
       else if (TREE_CODE (si->nonzero_chars) == SSA_NAME)
 	{
-	  wide_int min, max;
-	  // FIXME: Use range_query instead of global ranges.
-	  value_range_kind rng = get_range_info (si->nonzero_chars, &min, &max);
-	  if (rng == VR_RANGE)
+	  value_range r;
+	  RANGE_QUERY (cfun)->range_of_expr (r, si->nonzero_chars);
+	  if (r.kind () == VR_RANGE)
 	    {
-	      lenrng[0] = min.to_uhwi ();
-	      lenrng[1] = max.to_uhwi ();
+	      lenrng[0] = r.lower_bound ().to_uhwi ();
+	      lenrng[1] = r.upper_bound ().to_uhwi ();
 	      *nulterm = si->full_string_p;
 	    }
 	}
@@ -5301,17 +5318,13 @@ handle_integral_assign (gimple_stmt_iterator *gsi, bool *cleanup_eh,
 		  /* Reading a character before the final '\0'
 		     character.  Just set the value range to ~[0, 0]
 		     if we don't have anything better.  */
-		  wide_int min, max;
-		  signop sign = TYPE_SIGN (lhs_type);
-		  int prec = TYPE_PRECISION (lhs_type);
-		  // FIXME: Use range_query instead of global ranges.
-		  value_range_kind vr = get_range_info (lhs, &min, &max);
-		  if (vr == VR_VARYING
-		      || (vr == VR_RANGE
-			  && min == wi::min_value (prec, sign)
-			  && max == wi::max_value (prec, sign)))
-		    set_range_info (lhs, VR_ANTI_RANGE,
-				    wi::zero (prec), wi::zero (prec));
+		  value_range r;
+		  if (!RANGE_QUERY (cfun)->range_of_expr (r, lhs)
+		      || r.varying_p ())
+		    {
+		      r.set_nonzero (lhs_type);
+		      set_range_info (lhs, r);
+		    }
 		}
 	    }
 	}
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index a0238710e72..d8292777647 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -43,6 +43,7 @@
 #include "attribs.h"
 #include "tree-ssa.h"
 #include "tree-cfg.h"
+#include "gimple-range.h"
 
 /* The idea behind this analyzer is to generate set constraints from the
    program, then solve the resulting constraints in order to generate the
@@ -6740,7 +6741,9 @@ find_what_p_points_to (tree fndecl, tree p)
   struct ptr_info_def *pi;
   tree lookup_p = p;
   varinfo_t vi;
-  bool nonnull = get_ptr_nonnull (p);
+  value_range vr;
+  RANGE_QUERY (DECL_STRUCT_FUNCTION (fndecl))->range_of_expr (vr, p);
+  bool nonnull = vr.nonzero_p ();
 
   /* For parameters, get at the points-to set for the actual parm
      decl.  */
@@ -6758,8 +6761,7 @@ find_what_p_points_to (tree fndecl, tree p)
   pi->pt = find_what_var_points_to (fndecl, vi);
   /* Conservatively set to NULL from PTA (to true). */
   pi->pt.null = 1;
-  /* Preserve pointer nonnull computed by VRP.  See get_ptr_nonnull
-     in gcc/tree-ssaname.c for more information.  */
+  /* Preserve pointer nonnull globally computed.  */
   if (nonnull)
     set_ptr_nonnull (p);
 }
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index f55ce1939ac..b352f68b1b7 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "builtins.h"
 #include "calls.h"
+#include "gimple-range.h"
 
 /* This implements the pass that does predicate aware warning on uses of
    possibly uninitialized variables.  The pass first collects the set of
@@ -1606,11 +1607,14 @@ find_var_cmp_const (pred_chain_union preds, gphi *phi, gimple **flag_def,
 	       flag_var <= [min, max] ->  flag_var < [min, max+1]
 	       flag_var >= [min, max] ->  flag_var > [min-1, max]
 	     if no overflow/wrap.  */
-	  wide_int min, max;
 	  tree type = TREE_TYPE (cond_lhs);
+	  value_range r;
 	  if (!INTEGRAL_TYPE_P (type)
-	      || get_range_info (cond_rhs, &min, &max) != VR_RANGE)
+	      || !RANGE_QUERY (cfun)->range_of_expr (r, cond_rhs)
+	      || r.kind () != VR_RANGE)
 	    continue;
+	  wide_int min = r.lower_bound ();
+	  wide_int max = r.upper_bound ();
 	  if (code == LE_EXPR
 	      && max != wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)))
 	    {
diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
index 7f65c4ce839..225d831003f 100644
--- a/gcc/tree-switch-conversion.c
+++ b/gcc/tree-switch-conversion.c
@@ -50,6 +50,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "target.h"
 #include "tree-into-ssa.h"
 #include "omp-general.h"
+#include "gimple-range.h"
 
 /* ??? For lang_hooks.types.type_for_mode, but is there a word_mode
    type in the GIMPLE type system that is language-independent?  */
@@ -1553,12 +1554,15 @@ bit_test_cluster::emit (tree index_expr, tree index_type,
 
   /* If every possible relative value of the index expression is a valid shift
      amount, then we can merge the entry test in the bit test.  */
-  wide_int min, max;
   bool entry_test_needed;
+  value_range r;
   if (TREE_CODE (index_expr) == SSA_NAME
-      && get_range_info (index_expr, &min, &max) == VR_RANGE
-      && wi::leu_p (max - min, prec - 1))
+      && RANGE_QUERY (cfun)->range_of_expr (r, index_expr)
+      && r.kind () == VR_RANGE
+      && wi::leu_p (r.upper_bound () - r.lower_bound (), prec - 1))
     {
+      wide_int min = r.lower_bound ();
+      wide_int max = r.upper_bound ();
       tree index_type = TREE_TYPE (index_expr);
       minval = fold_convert (index_type, minval);
       wide_int iminval = wi::to_wide (minval);
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index 803de3fc287..99be2314029 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "predict.h"
 #include "tree-vector-builder.h"
 #include "vec-perm-indices.h"
+#include "gimple-range.h"
 
 /* Return true if we have a useful VR_RANGE range for VAR, storing it
    in *MIN_VALUE and *MAX_VALUE if so.  Note the range in the dump files.  */
@@ -55,7 +56,13 @@ along with GCC; see the file COPYING3.  If not see
 static bool
 vect_get_range_info (tree var, wide_int *min_value, wide_int *max_value)
 {
-  value_range_kind vr_type = get_range_info (var, min_value, max_value);
+  value_range vr;
+  RANGE_QUERY (cfun)->range_of_expr (vr, var);
+  if (vr.undefined_p ())
+    vr.set_varying (TREE_TYPE (var));
+  *min_value = wi::to_wide (vr.min ());
+  *max_value = wi::to_wide (vr.max ());
+  value_range_kind vr_type = vr.kind ();
   wide_int nonzero = get_nonzero_bits (var);
   signop sgn = TYPE_SIGN (TREE_TYPE (var));
   if (intersect_range_with_nonzero_bits (vr_type, min_value, max_value,
@@ -3437,13 +3444,14 @@ vect_recog_divmod_pattern (vec_info *vinfo,
       else
 	t3 = t2;
 
-      wide_int oprnd0_min, oprnd0_max;
       int msb = 1;
-      if (get_range_info (oprnd0, &oprnd0_min, &oprnd0_max) == VR_RANGE)
+      value_range r;
+      RANGE_QUERY (cfun)->range_of_expr (r, oprnd0);
+      if (r.kind () == VR_RANGE)
 	{
-	  if (!wi::neg_p (oprnd0_min, TYPE_SIGN (itype)))
+	  if (!wi::neg_p (r.lower_bound (), TYPE_SIGN (itype)))
 	    msb = 0;
-	  else if (wi::neg_p (oprnd0_max, TYPE_SIGN (itype)))
+	  else if (wi::neg_p (r.upper_bound (), TYPE_SIGN (itype)))
 	    msb = -1;
 	}
 
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index b0f1c47f05c..6a723efc0d8 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -228,7 +228,7 @@ intersect_range_with_nonzero_bits (enum value_range_kind vr_type,
 	  vr_type = VR_RANGE;
 	}
     }
-  if (vr_type == VR_RANGE)
+  if (vr_type == VR_RANGE || vr_type == VR_VARYING)
     {
       *max = wi::round_down_for_mask (*max, nonzero_bits);
 
@@ -1717,7 +1717,7 @@ register_edge_assert_for_2 (tree name, edge e,
          simply register the same assert for it.  */
       if (CONVERT_EXPR_CODE_P (rhs_code))
 	{
-	  wide_int rmin, rmax;
+	  value_range vr;
 	  tree rhs1 = gimple_assign_rhs1 (def_stmt);
 	  if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
 	      && TREE_CODE (rhs1) == SSA_NAME
@@ -1739,13 +1739,14 @@ register_edge_assert_for_2 (tree name, edge e,
 	      && int_fits_type_p (val, TREE_TYPE (rhs1))
 	      && ((TYPE_PRECISION (TREE_TYPE (name))
 		   > TYPE_PRECISION (TREE_TYPE (rhs1)))
-		  || (get_range_info (rhs1, &rmin, &rmax) == VR_RANGE
+		  || ((RANGE_QUERY (cfun)->range_of_expr (vr, rhs1)
+		       && vr.kind () == VR_RANGE)
 		      && wi::fits_to_tree_p
-			   (widest_int::from (rmin,
+			   (widest_int::from (vr.lower_bound (),
 					      TYPE_SIGN (TREE_TYPE (rhs1))),
 			    TREE_TYPE (name))
 		      && wi::fits_to_tree_p
-			   (widest_int::from (rmax,
+			   (widest_int::from (vr.upper_bound (),
 					      TYPE_SIGN (TREE_TYPE (rhs1))),
 			    TREE_TYPE (name)))))
 	    add_assert_info (asserts, rhs1, rhs1,
@@ -4631,16 +4632,14 @@ determine_value_range_1 (value_range *vr, tree expr)
     vr->set (expr);
   else
     {
-      value_range_kind kind;
-      wide_int min, max;
+      value_range r;
       /* For SSA names try to extract range info computed by VRP.  Otherwise
 	 fall back to varying.  */
       if (TREE_CODE (expr) == SSA_NAME
 	  && INTEGRAL_TYPE_P (TREE_TYPE (expr))
-	  && (kind = get_range_info (expr, &min, &max)) != VR_VARYING)
-	vr->set (wide_int_to_tree (TREE_TYPE (expr), min),
-		 wide_int_to_tree (TREE_TYPE (expr), max),
-		 kind);
+	  && RANGE_QUERY (cfun)->range_of_expr (r, expr)
+	  && !r.undefined_p ())
+	*vr = r;
       else
 	vr->set_varying (TREE_TYPE (expr));
     }
diff --git a/gcc/tree.c b/gcc/tree.c
index 31ac4245c9c..3d5111628b5 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -68,6 +68,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vector-builder.h"
 #include "gimple-fold.h"
 #include "escaped_string.h"
+#include "gimple-range.h"
 
 /* Tree code classes.  */
 
@@ -13834,8 +13835,8 @@ get_range_pos_neg (tree arg)
 
   if (TREE_CODE (arg) != SSA_NAME)
     return 3;
-  wide_int arg_min, arg_max;
-  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
+  value_range r;
+  while (!GLOBAL_RANGE_QUERY->range_of_expr (r, arg) || r.kind () != VR_RANGE)
     {
       gimple *g = SSA_NAME_DEF_STMT (arg);
       if (is_gimple_assign (g)
@@ -13861,16 +13862,16 @@ get_range_pos_neg (tree arg)
     {
       /* For unsigned values, the "positive" range comes
 	 below the "negative" range.  */
-      if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED))
+      if (!wi::neg_p (wi::sext (r.upper_bound (), prec), SIGNED))
 	return 1;
-      if (wi::neg_p (wi::sext (arg_min, prec), SIGNED))
+      if (wi::neg_p (wi::sext (r.lower_bound (), prec), SIGNED))
 	return 2;
     }
   else
     {
-      if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED))
+      if (!wi::neg_p (wi::sext (r.lower_bound (), prec), SIGNED))
 	return 1;
-      if (wi::neg_p (wi::sext (arg_max, prec), SIGNED))
+      if (wi::neg_p (wi::sext (r.upper_bound (), prec), SIGNED))
 	return 2;
     }
   return 3;
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index a89f0b646ae..02acb46cb20 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -117,14 +117,16 @@ vr_values::get_lattice_entry (const_tree var)
 	     default definitions of PARM_DECLs.  */
 	  if (POINTER_TYPE_P (TREE_TYPE (sym))
 	      && (nonnull_arg_p (sym)
-		  || get_ptr_nonnull (var)))
+		  || (GLOBAL_RANGE_QUERY->range_of_expr (*vr,
+						const_cast <tree> (var))
+		      && vr->nonzero_p ())))
 	    {
 	      vr->set_nonzero (TREE_TYPE (sym));
 	      vr->equiv_clear ();
 	    }
 	  else if (INTEGRAL_TYPE_P (TREE_TYPE (sym)))
 	    {
-	      get_range_info (var, *vr);
+	      GLOBAL_RANGE_QUERY->range_of_expr (*vr, const_cast <tree> (var));
 	      if (vr->undefined_p ())
 		vr->set_varying (TREE_TYPE (sym));
 	    }
@@ -262,7 +264,7 @@ vr_values::update_value_range (const_tree var, value_range_equiv *new_vr)
   if (INTEGRAL_TYPE_P (TREE_TYPE (var)))
     {
       value_range_equiv nr;
-      get_range_info (var, nr);
+      GLOBAL_RANGE_QUERY->range_of_expr (nr, const_cast <tree> (var));
       if (!nr.undefined_p ())
 	new_vr->intersect (&nr);
     }
@@ -3829,13 +3831,13 @@ simplify_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
       || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop))
     return false;
 
-  /* Get the value-range of the inner operand.  Use get_range_info in
+  /* Get the value-range of the inner operand.  Use global ranges in
      case innerop was created during substitute-and-fold.  */
   wide_int imin, imax;
   value_range vr;
   if (!INTEGRAL_TYPE_P (TREE_TYPE (innerop)))
     return false;
-  get_range_info (innerop, vr);
+  RANGE_QUERY (cfun)->range_of_expr (vr, innerop, stmt);
   if (vr.undefined_p () || vr.varying_p ())
     return false;
   innermin = widest_int::from (vr.lower_bound (), TYPE_SIGN (TREE_TYPE (innerop)));
-- 
2.31.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] Common API for accessing global and on-demand ranges.
  2021-05-25 11:06           ` Richard Biener
@ 2021-05-25 16:16             ` Aldy Hernandez
  2021-05-26 13:40               ` Andrew MacLeod
  2021-05-29  4:35               ` Jeff Law
  0 siblings, 2 replies; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-25 16:16 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC patches, Andrew MacLeod, Martin Sebor

[-- Attachment #1: Type: text/plain, Size: 427 bytes --]

The interface is now an inline function for get_range_query() and an 
external function for get_global_range_query), as discussed.

There are no magic cfun uses behind the scenes.

The annoying downcast is gone.

Passes can now decide if they want to export global ranges after they 
use a ranger.

I've adjusted the ChangeLog entries, as well as the commit text.

I've addressed everything discussed.

OK pending tests?

Aldy

[-- Attachment #2: 0001-Common-API-for-accessing-global-and-on-demand-ranges.patch --]
[-- Type: text/x-patch, Size: 15695 bytes --]

From eeb7627ddf686d5affb08dcad3674b560ef3ce6d Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Wed, 19 May 2021 18:27:05 +0200
Subject: [PATCH 1/5] 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.
---
 gcc/function.c            |   4 ++
 gcc/function.h            |  17 +++++
 gcc/gimple-range-cache.cc |   1 -
 gcc/gimple-range.cc       | 126 ++++++++++++++++++++++++++++++++++++++
 gcc/gimple-range.h        |  60 +++++-------------
 gcc/gimple-ssa-evrp.c     |   2 +-
 gcc/tree-vrp.c            |   2 +-
 gcc/value-query.cc        |   5 ++
 gcc/value-query.h         |   1 +
 gcc/vr-values.c           |   2 +-
 gcc/vr-values.h           |   2 +-
 11 files changed, 172 insertions(+), 50 deletions(-)

diff --git a/gcc/function.c b/gcc/function.c
index fc7b147b5f1..67576950983 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -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
diff --git a/gcc/function.h b/gcc/function.h
index 66cfa973808..0db51775e7c 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -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 */
diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 2c922e32913..c645d15f5af 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -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;
 }
 
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 710bc7f9632..409d1f75d7c 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -1402,3 +1402,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;
+}
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index f33156181bf..cb911798dae 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -53,7 +53,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;
 protected:
   bool calc_stmt (irange &r, gimple *s, tree name = NULL_TREE);
   bool range_of_range_op (irange &r, gimple *s);
@@ -130,50 +130,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.
 
@@ -202,4 +158,18 @@ private:
 // Temporary external interface to share with vr_values.
 bool range_of_builtin_call (range_query &query, irange &r, gcall *call);
 
+// 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
diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c
index 5f566ae0958..829fdcdaef2 100644
--- a/gcc/gimple-ssa-evrp.c
+++ b/gcc/gimple-ssa-evrp.c
@@ -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");
       }
   }
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 12e6e6f3e22..b0f1c47f05c 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -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");
     }
 
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 4bb0897c446..509d2d33cc5 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -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>
diff --git a/gcc/value-query.h b/gcc/value-query.h
index e2cbc6852b0..5eff9317ed5 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -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 ();
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index b1bf53af9e0..a89f0b646ae 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -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;
 
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index 8c1b2e0a292..81b9131f7f1 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -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,
-- 
2.31.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun).
  2021-05-21 11:39 ` [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun) Aldy Hernandez
  2021-05-25  8:43   ` Richard Biener
@ 2021-05-25 16:17   ` Aldy Hernandez
  2021-05-25 16:28     ` Jeff Law
                       ` (2 more replies)
  1 sibling, 3 replies; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-25 16:17 UTC (permalink / raw)
  To: GCC patches, Andrew MacLeod; +Cc: Jeff Law, Martin Sebor

[-- Attachment #1: Type: text/plain, Size: 53 bytes --]

Adjustments per discussion.

OK pending tests?

Aldy

[-- Attachment #2: 0003-Convert-Walloca-pass-to-get_range_query.patch --]
[-- Type: text/x-patch, Size: 4724 bytes --]

From 97bedf7dc0a7860802461b5fd3e72b687076ae30 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Wed, 19 May 2021 18:27:47 +0200
Subject: [PATCH 3/5] Convert Walloca pass to get_range_query.

This patch converts the Walloca pass to use an on-demand ranger
accesible with get_range_query instead of having to create a ranger and pass
it around.

gcc/ChangeLog:

	* gimple-ssa-warn-alloca.c (alloca_call_type): Use
	  get_range_query instead of query argument.
	(pass_walloca::execute): Enable and disable global ranger.
---
 gcc/gimple-ssa-warn-alloca.c                 | 10 ++++++----
 gcc/testsuite/gcc.dg/Wstringop-overflow-55.c |  8 ++++----
 gcc/testsuite/gcc.dg/pr80776-1.c             |  4 +---
 3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
index e9a24d4d1d0..72480f1d8cb 100644
--- a/gcc/gimple-ssa-warn-alloca.c
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -165,7 +165,7 @@ adjusted_warn_limit (bool idx)
 // call was created by the gimplifier for a VLA.
 
 static class alloca_type_and_limit
-alloca_call_type (range_query &query, gimple *stmt, bool is_vla)
+alloca_call_type (gimple *stmt, bool is_vla)
 {
   gcc_assert (gimple_alloca_call_p (stmt));
   tree len = gimple_call_arg (stmt, 0);
@@ -217,7 +217,7 @@ alloca_call_type (range_query &query, gimple *stmt, bool is_vla)
   int_range_max r;
   if (warn_limit_specified_p (is_vla)
       && TREE_CODE (len) == SSA_NAME
-      && query.range_of_expr (r, len, stmt)
+      && get_range_query (cfun)->range_of_expr (r, len, stmt)
       && !r.varying_p ())
     {
       // The invalid bits are anything outside of [0, MAX_SIZE].
@@ -256,7 +256,7 @@ in_loop_p (gimple *stmt)
 unsigned int
 pass_walloca::execute (function *fun)
 {
-  gimple_ranger ranger;
+  gimple_ranger *ranger = enable_ranger (fun);
   basic_block bb;
   FOR_EACH_BB_FN (bb, fun)
     {
@@ -290,7 +290,7 @@ pass_walloca::execute (function *fun)
 	    continue;
 
 	  class alloca_type_and_limit t
-	    = alloca_call_type (ranger, stmt, is_vla);
+	    = alloca_call_type (stmt, is_vla);
 
 	  unsigned HOST_WIDE_INT adjusted_alloca_limit
 	    = adjusted_warn_limit (false);
@@ -383,6 +383,8 @@ pass_walloca::execute (function *fun)
 	    }
 	}
     }
+  ranger->export_global_ranges ();
+  disable_ranger (fun);
   return 0;
 }
 
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c
index 25f5b82d9be..8df5cb629ae 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c
@@ -66,7 +66,7 @@ void warn_ptrdiff_anti_range_add (ptrdiff_t i)
 {
   i |= 1;
 
-  char ca5[5];              // { dg-message "at offset \\\[1, 5]" "pr?????" { xfail *-*-* } }
+  char ca5[5];              // { dg-message "at offset \\\[1, 5]" "pr?????" }
   char *p0 = ca5;           // offset
   char *p1 = p0 + i;        //  1-5
   char *p2 = p1 + i;        //  2-5
@@ -74,7 +74,7 @@ void warn_ptrdiff_anti_range_add (ptrdiff_t i)
   char *p4 = p3 + i;        //  4-5
   char *p5 = p4 + i;        //   5
 
-  memset (p5, 0, 5);        // { dg-warning "writing 5 bytes into a region of size 0" "pr?????" { xfail *-*-* } }
+  memset (p5, 0, 5);        // { dg-warning "writing 5 bytes into a region of size" "pr?????" }
 
   sink (p0, p1, p2, p3, p4, p5);
 }
@@ -83,7 +83,7 @@ void warn_int_anti_range (int i)
 {
   i |= 1;
 
-  char ca5[5];              // { dg-message "at offset \\\[1, 5]" "pr?????" { xfail *-*-* } }
+  char ca5[5];              // { dg-message "at offset \\\[1, 5]" "pr?????" }
   char *p0 = ca5;           // offset
   char *p1 = p0 + i;        //  1-5
   char *p2 = p1 + i;        //  2-5
@@ -91,7 +91,7 @@ void warn_int_anti_range (int i)
   char *p4 = p3 + i;        //  4-5
   char *p5 = p4 + i;        //   5
 
-  memset (p5, 0, 5);        // { dg-warning "writing 5 bytes into a region of size 0" "pr?????" { xfail *-*-* } }
+  memset (p5, 0, 5);        // { dg-warning "writing 5 bytes into a region of size" "pr?????" }
 
   sink (p0, p1, p2, p3, p4, p5);
 }
diff --git a/gcc/testsuite/gcc.dg/pr80776-1.c b/gcc/testsuite/gcc.dg/pr80776-1.c
index af41c0c2ffa..f3a120b6744 100644
--- a/gcc/testsuite/gcc.dg/pr80776-1.c
+++ b/gcc/testsuite/gcc.dg/pr80776-1.c
@@ -17,7 +17,5 @@ Foo (void)
     __builtin_unreachable ();
   if (! (0 <= i && i <= 999999))
     __builtin_unreachable ();
-  /* The correctness bits for [E]VRP cannot handle chained conditionals
-     when deciding to ignore a unreachable branch for setting SSA range info. */
-  sprintf (number, "%d", i); /* { dg-bogus "writing" "" { xfail *-*-* } } */
+  sprintf (number, "%d", i); /* { dg-bogus "writing" "" } */
 }
-- 
2.31.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/5] Convert evrp pass to RANGE_QUERY(cfun).
  2021-05-21 11:39 ` [PATCH 3/5] Convert evrp " Aldy Hernandez
@ 2021-05-25 16:18   ` Aldy Hernandez
  2021-05-27  2:34     ` H.J. Lu
  0 siblings, 1 reply; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-25 16:18 UTC (permalink / raw)
  To: GCC patches, Andrew MacLeod; +Cc: Jeff Law, Martin Sebor

[-- Attachment #1: Type: text/plain, Size: 53 bytes --]

Adjustments per discussion.

OK pending tests?

Aldy

[-- Attachment #2: 0002-Convert-evrp-pass-to-get_range_query.patch --]
[-- Type: text/x-patch, Size: 1981 bytes --]

From 1c275296ab64cd877bce795b9964532c8655fa3f Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Tue, 25 May 2021 17:44:51 +0200
Subject: [PATCH 2/5] Convert evrp pass to get_range_query.

gcc/ChangeLog:

	* gimple-ssa-evrp.c (rvrp_folder::rvrp_folder): Call
	enable_ranger.
	(rvrp_folder::~rvrp_folder): Call disable_ranger.
	(hybrid_folder::hybrid_folder): Call enable_ranger.
	(hybrid_folder::~hybrid_folder): Call disable_ranger.
---
 gcc/gimple-ssa-evrp.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c
index 829fdcdaef2..118d10365a0 100644
--- a/gcc/gimple-ssa-evrp.c
+++ b/gcc/gimple-ssa-evrp.c
@@ -117,11 +117,8 @@ class rvrp_folder : public substitute_and_fold_engine
 public:
 
   rvrp_folder () : substitute_and_fold_engine (), m_simplifier ()
-  { 
-    if (param_evrp_mode & EVRP_MODE_TRACE)
-      m_ranger = new trace_ranger ();
-    else
-      m_ranger = new gimple_ranger ();
+  {
+    m_ranger = enable_ranger (cfun);
     m_simplifier.set_range_query (m_ranger);
   }
       
@@ -129,7 +126,9 @@ public:
   {
     if (dump_file && (dump_flags & TDF_DETAILS))
       m_ranger->dump (dump_file);
-    delete m_ranger;
+
+    m_ranger->export_global_ranges ();
+    disable_ranger (cfun);
   }
 
   tree value_of_expr (tree name, gimple *s = NULL) OVERRIDE
@@ -175,10 +174,7 @@ class hybrid_folder : public evrp_folder
 public:
   hybrid_folder (bool evrp_first)
   {
-    if (param_evrp_mode & EVRP_MODE_TRACE)
-      m_ranger = new trace_ranger ();
-    else
-      m_ranger = new gimple_ranger ();
+    m_ranger = enable_ranger (cfun);
 
     if (evrp_first)
       {
@@ -196,7 +192,9 @@ public:
   {
     if (dump_file && (dump_flags & TDF_DETAILS))
       m_ranger->dump (dump_file);
-    delete m_ranger;
+
+    m_ranger->export_global_ranges ();
+    disable_ranger (cfun);
   }
 
   bool fold_stmt (gimple_stmt_iterator *gsi) OVERRIDE
-- 
2.31.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 4/5] Convert remaining passes to RANGE_QUERY.
  2021-05-21 11:39 ` [PATCH 4/5] Convert remaining passes to RANGE_QUERY Aldy Hernandez
  2021-05-24 19:34   ` Martin Sebor
@ 2021-05-25 16:19   ` Aldy Hernandez
  1 sibling, 0 replies; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-25 16:19 UTC (permalink / raw)
  To: GCC patches, Andrew MacLeod; +Cc: Jeff Law, Martin Sebor

[-- Attachment #1: Type: text/plain, Size: 53 bytes --]

Adjustments per discussion.

OK pending tests?

Aldy

[-- Attachment #2: 0004-Convert-remaining-passes-to-get_range_query.patch --]
[-- Type: text/x-patch, Size: 48923 bytes --]

From d701627d2b0a3cdfea7a11b3b4cf4105db08dcf5 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Wed, 19 May 2021 18:44:08 +0200
Subject: [PATCH 4/5] Convert remaining passes to get_range_query.

This patch converts the remaining users of get_range_info and
get_ptr_nonnull to the get_range_query API.

No effort was made to move passes away from VR_ANTI_RANGE, or any other
use of deprecated methods.  This was a straight up conversion to the new
API, nothing else.

gcc/ChangeLog:

	* builtins.c (check_nul_terminated_array): Convert to get_range_query.
	(expand_builtin_strnlen): Same.
	(determine_block_size): Same.
	* fold-const.c (expr_not_equal_to): Same.
	* gimple-fold.c (size_must_be_zero_p): Same.
	* gimple-match-head.c: Include gimple-range.h.
	* gimple-pretty-print.c (dump_ssaname_info): Convert to get_range_query.
	* gimple-ssa-warn-restrict.c
	(builtin_memref::extend_offset_range): Same.
	* graphite-sese-to-poly.c (add_param_constraints): Same.
	* internal-fn.c (get_min_precision): Same.
	* ipa-fnsummary.c (set_switch_stmt_execution_predicate): Same.
	* ipa-prop.c (ipa_compute_jump_functions_for_edge): Same.
	* match.pd: Same.
	* tree-data-ref.c (split_constant_offset): Same.
	(dr_step_indicator): Same.
	* tree-dfa.c (get_ref_base_and_extent): Same.
	* tree-scalar-evolution.c (iv_can_overflow_p): Same.
	* tree-ssa-loop-niter.c (refine_value_range_using_guard): Same.
	(determine_value_range): Same.
	(record_nonwrapping_iv): Same.
	(infer_loop_bounds_from_signedness): Same.
	(scev_var_range_cant_overflow): Same.
	* tree-ssa-phiopt.c (two_value_replacement): Same.
	* tree-ssa-pre.c (insert_into_preds_of_block): Same.
	* tree-ssa-reassoc.c (optimize_range_tests_to_bit_test): Same.
	* tree-ssa-strlen.c (handle_builtin_stxncpy_strncat): Same.
	(get_range): Same.
	(dump_strlen_info): Same.
	(set_strlen_range): Same.
	(maybe_diag_stxncpy_trunc): Same.
	(get_len_or_size): Same.
	(handle_integral_assign): Same.
	* tree-ssa-structalias.c (find_what_p_points_to): Same.
	* tree-ssa-uninit.c (find_var_cmp_const): Same.
	* tree-switch-conversion.c (bit_test_cluster::emit): Same.
	* tree-vect-patterns.c (vect_get_range_info): Same.
	(vect_recog_divmod_pattern): Same.
	* tree-vrp.c (intersect_range_with_nonzero_bits): Same.
	(register_edge_assert_for_2): Same.
	(determine_value_range_1): Same.
	* tree.c (get_range_pos_neg): Same.
	* vr-values.c (vr_values::get_lattice_entry): Same.
	(vr_values::update_value_range): Same.
	(simplify_conversion_using_ranges): Same.
---
 gcc/builtins.c                 | 40 ++++++++++------
 gcc/fold-const.c               |  8 +++-
 gcc/gimple-fold.c              |  7 ++-
 gcc/gimple-match-head.c        |  1 +
 gcc/gimple-pretty-print.c      | 12 ++++-
 gcc/gimple-ssa-warn-restrict.c |  8 +++-
 gcc/graphite-sese-to-poly.c    |  9 +++-
 gcc/internal-fn.c              | 14 +++---
 gcc/ipa-fnsummary.c            | 11 ++++-
 gcc/ipa-prop.c                 | 16 +++----
 gcc/match.pd                   | 19 ++++++--
 gcc/tree-data-ref.c            | 24 ++++++++--
 gcc/tree-dfa.c                 | 14 +++++-
 gcc/tree-scalar-evolution.c    | 13 +++++-
 gcc/tree-ssa-loop-niter.c      | 81 +++++++++++++++++++++-----------
 gcc/tree-ssa-phiopt.c          | 11 ++++-
 gcc/tree-ssa-pre.c             | 19 ++++----
 gcc/tree-ssa-reassoc.c         |  9 ++--
 gcc/tree-ssa-strlen.c          | 85 ++++++++++++++++++++--------------
 gcc/tree-ssa-structalias.c     |  8 ++--
 gcc/tree-ssa-uninit.c          |  8 +++-
 gcc/tree-switch-conversion.c   | 10 ++--
 gcc/tree-vect-patterns.c       | 18 +++++--
 gcc/tree-vrp.c                 | 21 ++++-----
 gcc/tree.c                     | 13 +++---
 gcc/vr-values.c                | 12 +++--
 26 files changed, 332 insertions(+), 159 deletions(-)

diff --git a/gcc/builtins.c b/gcc/builtins.c
index e1b284846b1..135d6bbc2d0 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-outof-ssa.h"
 #include "attr-fnspec.h"
 #include "demangle.h"
+#include "gimple-range.h"
 
 struct target_builtins default_target_builtins;
 #if SWITCHABLE_TARGET
@@ -1214,14 +1215,15 @@ check_nul_terminated_array (tree expr, tree src,
   wide_int bndrng[2];
   if (bound)
     {
-      if (TREE_CODE (bound) == INTEGER_CST)
-	bndrng[0] = bndrng[1] = wi::to_wide (bound);
-      else
-	{
-	  value_range_kind rng = get_range_info (bound, bndrng, bndrng + 1);
-	  if (rng != VR_RANGE)
-	    return true;
-	}
+      value_range r;
+
+      get_global_range_query ()->range_of_expr (r, bound);
+
+      if (r.kind () != VR_RANGE)
+	return true;
+
+      bndrng[0] = r.lower_bound ();
+      bndrng[1] = r.upper_bound ();
 
       if (exact)
 	{
@@ -3827,9 +3829,12 @@ expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
     return NULL_RTX;
 
   wide_int min, max;
-  enum value_range_kind rng = get_range_info (bound, &min, &max);
-  if (rng != VR_RANGE)
+  value_range r;
+  get_global_range_query ()->range_of_expr (r, bound);
+  if (r.kind () != VR_RANGE)
     return NULL_RTX;
+  min = r.lower_bound ();
+  max = r.upper_bound ();
 
   if (!len || TREE_CODE (len) != INTEGER_CST)
     {
@@ -3897,7 +3902,16 @@ determine_block_size (tree len, rtx len_rtx,
 	*probable_max_size = *max_size = GET_MODE_MASK (GET_MODE (len_rtx));
 
       if (TREE_CODE (len) == SSA_NAME)
-	range_type = get_range_info (len, &min, &max);
+	{
+	  value_range r;
+	  get_global_range_query ()->range_of_expr (r, len);
+	  range_type = r.kind ();
+	  if (range_type != VR_UNDEFINED)
+	    {
+	      min = wi::to_wide (r.min ());
+	      max = wi::to_wide (r.max ());
+	    }
+	}
       if (range_type == VR_RANGE)
 	{
 	  if (wi::fits_uhwi_p (min) && *min_size < min.to_uhwi ())
@@ -4914,8 +4928,8 @@ check_read_access (tree exp, tree src, tree bound /* = NULL_TREE */,
 /* If STMT is a call to an allocation function, returns the constant
    maximum size of the object allocated by the call represented as
    sizetype.  If nonnull, sets RNG1[] to the range of the size.
-   When nonnull, uses RVALS for range information, otherwise calls
-   get_range_info to get it.
+   When nonnull, uses RVALS for range information, otherwise gets global
+   range info.
    Returns null when STMT is not a call to a valid allocation function.  */
 
 tree
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 5a41524702b..4a4358362e1 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -83,6 +83,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vector-builder.h"
 #include "vec-perm-indices.h"
 #include "asan.h"
+#include "gimple-range.h"
 
 /* Nonzero if we are folding constants inside an initializer; zero
    otherwise.  */
@@ -10686,7 +10687,12 @@ expr_not_equal_to (tree t, const wide_int &w)
     case SSA_NAME:
       if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
 	return false;
-      get_range_info (t, vr);
+
+      if (cfun)
+	get_range_query (cfun)->range_of_expr (vr, t);
+      else
+	get_global_range_query ()->range_of_expr (vr, t);
+
       if (!vr.undefined_p ()
 	  && !vr.contains_p (wide_int_to_tree (TREE_TYPE (t), w)))
 	return true;
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 68717cf1542..eaf0fb76b66 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -873,7 +873,12 @@ size_must_be_zero_p (tree size)
   value_range valid_range (build_int_cst (type, 0),
 			   wide_int_to_tree (type, ssize_max));
   value_range vr;
-  get_range_info (size, vr);
+  if (cfun)
+    get_range_query (cfun)->range_of_expr (vr, size);
+  else
+    get_global_range_query ()->range_of_expr (vr, size);
+  if (vr.undefined_p ())
+    vr.set_varying (TREE_TYPE (size));
   vr.intersect (&valid_range);
   return vr.zero_p ();
 }
diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c
index b084a31572a..7112c116835 100644
--- a/gcc/gimple-match-head.c
+++ b/gcc/gimple-match-head.c
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-eh.h"
 #include "dbgcnt.h"
 #include "tm.h"
+#include "gimple-range.h"
 
 /* Forward declarations of the private auto-generated matchers.
    They expect valueized operands in canonical order and do not
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 0ef01e6420b..c9c0a66ee30 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "asan.h"
 #include "cfgloop.h"
+#include "gimple-range.h"
 
 /* Disable warnings about quoting issues in the pp_xxx calls below
    that (intentionally) don't follow GCC diagnostic conventions.  */
@@ -2263,8 +2264,17 @@ dump_ssaname_info (pretty_printer *buffer, tree node, int spc)
       && SSA_NAME_RANGE_INFO (node))
     {
       wide_int min, max, nonzero_bits;
-      value_range_kind range_type = get_range_info (node, &min, &max);
+      value_range r;
 
+      get_global_range_query ()->range_of_expr (r, node);
+      value_range_kind range_type = r.kind ();
+      if (!r.undefined_p ())
+	{
+	  min = wi::to_wide (r.min ());
+	  max = wi::to_wide (r.max ());
+	}
+
+      // FIXME: Use irange::dump() instead.
       if (range_type == VR_VARYING)
 	pp_printf (buffer, "# RANGE VR_VARYING");
       else if (range_type == VR_RANGE || range_type == VR_ANTI_RANGE)
diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
index ad37f20afaa..c8c9f9581a8 100644
--- a/gcc/gimple-ssa-warn-restrict.c
+++ b/gcc/gimple-ssa-warn-restrict.c
@@ -349,7 +349,13 @@ builtin_memref::extend_offset_range (tree offset)
 	  /* There is a global version here because
 	     check_bounds_or_overlap may be called from gimple
 	     fold during gimple lowering.  */
-	  rng = get_range_info (offset, &min, &max);
+	  get_range_query (cfun)->range_of_expr (vr, offset, stmt);
+	  rng = vr.kind ();
+	  if (!vr.undefined_p ())
+	    {
+	      min = wi::to_wide (vr.min ());
+	      max = wi::to_wide (vr.max ());
+	    }
 	}
       if (rng == VR_ANTI_RANGE && wi::lts_p (max, min))
 	{
diff --git a/gcc/graphite-sese-to-poly.c b/gcc/graphite-sese-to-poly.c
index eebf2e02cfc..99ea0327b1a 100644
--- a/gcc/graphite-sese-to-poly.c
+++ b/gcc/graphite-sese-to-poly.c
@@ -418,13 +418,18 @@ static void
 add_param_constraints (scop_p scop, graphite_dim_t p, tree parameter)
 {
   tree type = TREE_TYPE (parameter);
+  value_range r;
   wide_int min, max;
 
   gcc_assert (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type));
 
   if (INTEGRAL_TYPE_P (type)
-      && get_range_info (parameter, &min, &max) == VR_RANGE)
-    ;
+      && get_range_query (cfun)->range_of_expr (r, parameter)
+      && !r.undefined_p ())
+    {
+      min = r.lower_bound ();
+      max = r.upper_bound ();
+    }
   else
     {
       min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index d209a52f823..f06c2711cb7 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "ssa-iterators.h"
 #include "explow.h"
 #include "rtl-iter.h"
+#include "gimple-range.h"
 
 /* The names of each internal function, indexed by function number.  */
 const char *const internal_fn_name_array[] = {
@@ -680,8 +681,9 @@ get_min_precision (tree arg, signop sign)
     }
   if (TREE_CODE (arg) != SSA_NAME)
     return prec + (orig_sign != sign);
-  wide_int arg_min, arg_max;
-  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
+  value_range r;
+  while (!get_global_range_query ()->range_of_expr (r, arg)
+	 || r.kind () != VR_RANGE)
     {
       gimple *g = SSA_NAME_DEF_STMT (arg);
       if (is_gimple_assign (g)
@@ -709,14 +711,14 @@ get_min_precision (tree arg, signop sign)
     }
   if (sign == TYPE_SIGN (TREE_TYPE (arg)))
     {
-      int p1 = wi::min_precision (arg_min, sign);
-      int p2 = wi::min_precision (arg_max, sign);
+      int p1 = wi::min_precision (r.lower_bound (), sign);
+      int p2 = wi::min_precision (r.upper_bound (), sign);
       p1 = MAX (p1, p2);
       prec = MIN (prec, p1);
     }
-  else if (sign == UNSIGNED && !wi::neg_p (arg_min, SIGNED))
+  else if (sign == UNSIGNED && !wi::neg_p (r.lower_bound (), SIGNED))
     {
-      int p = wi::min_precision (arg_max, UNSIGNED);
+      int p = wi::min_precision (r.upper_bound (), UNSIGNED);
       prec = MIN (prec, p);
     }
   return prec + (orig_sign != sign);
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 4e5be812734..95d28757f95 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -85,6 +85,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "tree-into-ssa.h"
 #include "symtab-clones.h"
+#include "gimple-range.h"
 
 /* Summaries.  */
 fast_function_summary <ipa_fn_summary *, va_gc> *ipa_fn_summaries;
@@ -1687,8 +1688,14 @@ set_switch_stmt_execution_predicate (struct ipa_func_body_info *fbi,
   int bound_limit = opt_for_fn (fbi->node->decl,
 				param_ipa_max_switch_predicate_bounds);
   int bound_count = 0;
-  wide_int vr_wmin, vr_wmax;
-  value_range_kind vr_type = get_range_info (op, &vr_wmin, &vr_wmax);
+  value_range vr;
+
+  get_range_query (cfun)->range_of_expr (vr, op);
+  if (vr.undefined_p ())
+    vr.set_varying (TREE_TYPE (op));
+  value_range_kind vr_type = vr.kind ();
+  wide_int vr_wmin = wi::to_wide (vr.min ());
+  wide_int vr_wmax = wi::to_wide (vr.max ());
 
   FOR_EACH_EDGE (e, ei, bb->succs)
     {
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 0591ef1b569..f74d2e17b69 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -55,6 +55,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "options.h"
 #include "symtab-clones.h"
 #include "attr-fnspec.h"
+#include "gimple-range.h"
 
 /* Function summary where the parameter infos are actually stored. */
 ipa_node_params_t *ipa_node_params_sum = NULL;
@@ -2237,6 +2238,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
   gcall *call = cs->call_stmt;
   int n, arg_num = gimple_call_num_args (call);
   bool useful_context = false;
+  value_range vr;
 
   if (arg_num == 0 || args->jump_functions)
     return;
@@ -2274,7 +2276,8 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 
 	  if (TREE_CODE (arg) == SSA_NAME
 	      && param_type
-	      && get_ptr_nonnull (arg))
+	      && get_range_query (cfun)->range_of_expr (vr, arg)
+	      && vr.nonzero_p ())
 	    addr_nonzero = true;
 	  else if (tree_single_nonzero_warnv_p (arg, &strict_overflow))
 	    addr_nonzero = true;
@@ -2289,19 +2292,14 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 	}
       else
 	{
-	  wide_int min, max;
-	  value_range_kind kind;
 	  if (TREE_CODE (arg) == SSA_NAME
 	      && param_type
-	      && (kind = get_range_info (arg, &min, &max))
-	      && (kind == VR_RANGE || kind == VR_ANTI_RANGE))
+	      && get_range_query (cfun)->range_of_expr (vr, arg)
+	      && !vr.undefined_p ())
 	    {
 	      value_range resvr;
-	      value_range tmpvr (wide_int_to_tree (TREE_TYPE (arg), min),
-				 wide_int_to_tree (TREE_TYPE (arg), max),
-				 kind);
 	      range_fold_unary_expr (&resvr, NOP_EXPR, param_type,
-				     &tmpvr, TREE_TYPE (arg));
+				     &vr, TREE_TYPE (arg));
 	      if (!resvr.undefined_p () && !resvr.varying_p ())
 		ipa_set_jfunc_vr (jfunc, &resvr);
 	      else
diff --git a/gcc/match.pd b/gcc/match.pd
index cdb87636951..6be616fb2aa 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -663,11 +663,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (with
      {
        bool overflowed = true;
-       wide_int wmin0, wmax0, wmin1, wmax1;
+       value_range vr0, vr1;
        if (INTEGRAL_TYPE_P (type)
-	   && get_range_info (@0, &wmin0, &wmax0) == VR_RANGE
-	   && get_range_info (@1, &wmin1, &wmax1) == VR_RANGE)
+	   && get_global_range_query ()->range_of_expr (vr0, @0)
+	   && get_global_range_query ()->range_of_expr (vr1, @1)
+	   && vr0.kind () == VR_RANGE
+	   && vr1.kind () == VR_RANGE)
 	 {
+	   wide_int wmin0 = vr0.lower_bound ();
+	   wide_int wmax0 = vr0.upper_bound ();
+	   wide_int wmin1 = vr1.lower_bound ();
+	   wide_int wmax1 = vr1.upper_bound ();
 	   /* If the multiplication can't overflow/wrap around, then
 	      it can be optimized too.  */
 	   wi::overflow_type min_ovf, max_ovf;
@@ -2509,9 +2515,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 	  = wide_int::from (wi::to_wide (@1), TYPE_PRECISION (inner_type),
 			    TYPE_SIGN (inner_type));
 
-        wide_int wmin0, wmax0;
-        if (get_range_info (@0, &wmin0, &wmax0) == VR_RANGE)
+	value_range vr;
+	if (get_global_range_query ()->range_of_expr (vr, @0)
+	    && vr.kind () == VR_RANGE)
           {
+	    wide_int wmin0 = vr.lower_bound ();
+	    wide_int wmax0 = vr.upper_bound ();
             wi::add (wmin0, w1, TYPE_SIGN (inner_type), &min_ovf);
             wi::add (wmax0, w1, TYPE_SIGN (inner_type), &max_ovf);
           }
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index e6dd5f15bed..09d46671565 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -1035,14 +1035,23 @@ split_constant_offset (tree exp, tree *var, tree *off, value_range *exp_range,
       *exp_range = type;
       if (code == SSA_NAME)
 	{
-	  wide_int var_min, var_max;
-	  value_range_kind vr_kind = get_range_info (exp, &var_min, &var_max);
+	  value_range vr;
+	  get_range_query (cfun)->range_of_expr (vr, exp);
+	  if (vr.undefined_p ())
+	    vr.set_varying (TREE_TYPE (exp));
+	  wide_int var_min = wi::to_wide (vr.min ());
+	  wide_int var_max = wi::to_wide (vr.max ());
+	  value_range_kind vr_kind = vr.kind ();
 	  wide_int var_nonzero = get_nonzero_bits (exp);
 	  vr_kind = intersect_range_with_nonzero_bits (vr_kind,
 						       &var_min, &var_max,
 						       var_nonzero,
 						       TYPE_SIGN (type));
-	  if (vr_kind == VR_RANGE)
+	  /* This check for VR_VARYING is here because the old code
+	     using get_range_info would return VR_RANGE for the entire
+	     domain, instead of VR_VARYING.  The new code normalizes
+	     full-domain ranges to VR_VARYING.  */
+	  if (vr_kind == VR_RANGE || vr_kind == VR_VARYING)
 	    *exp_range = value_range (type, var_min, var_max);
 	}
     }
@@ -6298,12 +6307,19 @@ dr_step_indicator (struct data_reference *dr, int useful_min)
 
       /* Get the range of values that the unconverted step actually has.  */
       wide_int step_min, step_max;
+      value_range vr;
       if (TREE_CODE (step) != SSA_NAME
-	  || get_range_info (step, &step_min, &step_max) != VR_RANGE)
+	  || !get_range_query (cfun)->range_of_expr (vr, step)
+	  || vr.kind () != VR_RANGE)
 	{
 	  step_min = wi::to_wide (TYPE_MIN_VALUE (type));
 	  step_max = wi::to_wide (TYPE_MAX_VALUE (type));
 	}
+      else
+	{
+	  step_min = vr.lower_bound ();
+	  step_max = vr.upper_bound ();
+	}
 
       /* Check whether the unconverted step has an acceptable range.  */
       signop sgn = TYPE_SIGN (type);
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 0482b05e26c..b6becf1208c 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-iterator.h"
 #include "gimple-walk.h"
 #include "tree-dfa.h"
+#include "gimple-range.h"
 
 /* Build and maintain data flow information for trees.  */
 
@@ -530,14 +531,23 @@ get_ref_base_and_extent (tree exp, poly_int64_pod *poffset,
 		   index.  */
 		seen_variable_array_ref = true;
 
-		wide_int min, max;
+		value_range vr;
+		range_query *query;
+		if (cfun)
+		  query = get_range_query (cfun);
+		else
+		  query = get_global_range_query ();
+
 		if (TREE_CODE (index) == SSA_NAME
 		    && (low_bound = array_ref_low_bound (exp),
 			poly_int_tree_p (low_bound))
 		    && (unit_size = array_ref_element_size (exp),
 			TREE_CODE (unit_size) == INTEGER_CST)
-		    && get_range_info (index, &min, &max) == VR_RANGE)
+		    && query->range_of_expr (vr, index)
+		    && vr.kind () == VR_RANGE)
 		  {
+		    wide_int min = vr.lower_bound ();
+		    wide_int max = vr.upper_bound ();
 		    poly_offset_int lbound = wi::to_poly_offset (low_bound);
 		    /* Try to constrain maxsize with range information.  */
 		    offset_int omax
diff --git a/gcc/tree-scalar-evolution.c b/gcc/tree-scalar-evolution.c
index ff052be1021..b22d49a0ab6 100644
--- a/gcc/tree-scalar-evolution.c
+++ b/gcc/tree-scalar-evolution.c
@@ -3039,18 +3039,27 @@ iv_can_overflow_p (class loop *loop, tree type, tree base, tree step)
   widest_int nit;
   wide_int base_min, base_max, step_min, step_max, type_min, type_max;
   signop sgn = TYPE_SIGN (type);
+  value_range r;
 
   if (integer_zerop (step))
     return false;
 
   if (!INTEGRAL_TYPE_P (TREE_TYPE (base))
-      || get_range_info (base, &base_min, &base_max) != VR_RANGE)
+      || !get_range_query (cfun)->range_of_expr (r, base)
+      || r.kind () != VR_RANGE)
     return true;
 
+  base_min = r.lower_bound ();
+  base_max = r.upper_bound ();
+
   if (!INTEGRAL_TYPE_P (TREE_TYPE (step))
-      || get_range_info (step, &step_min, &step_max) != VR_RANGE)
+      || !get_range_query (cfun)->range_of_expr (r, step)
+      || r.kind () != VR_RANGE)
     return true;
 
+  step_min = r.lower_bound ();
+  step_max = r.upper_bound ();
+
   if (!get_max_loop_iterations (loop, &nit))
     return true;
 
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 3817ec423e7..b5add827018 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-chrec.h"
 #include "tree-scalar-evolution.h"
 #include "tree-dfa.h"
+#include "gimple-range.h"
 
 
 /* The maximum number of dominator BBs we search for conditions
@@ -121,7 +122,6 @@ refine_value_range_using_guard (tree type, tree var,
   tree varc0, varc1, ctype;
   mpz_t offc0, offc1;
   mpz_t mint, maxt, minc1, maxc1;
-  wide_int minv, maxv;
   bool no_wrap = nowrap_type_p (type);
   bool c0_ok, c1_ok;
   signop sgn = TYPE_SIGN (type);
@@ -221,6 +221,7 @@ refine_value_range_using_guard (tree type, tree var,
   get_type_static_bounds (type, mint, maxt);
   mpz_init (minc1);
   mpz_init (maxc1);
+  value_range r;
   /* Setup range information for varc1.  */
   if (integer_zerop (varc1))
     {
@@ -229,11 +230,12 @@ refine_value_range_using_guard (tree type, tree var,
     }
   else if (TREE_CODE (varc1) == SSA_NAME
 	   && INTEGRAL_TYPE_P (type)
-	   && get_range_info (varc1, &minv, &maxv) == VR_RANGE)
+	   && get_range_query (cfun)->range_of_expr (r, varc1)
+	   && r.kind () == VR_RANGE)
     {
-      gcc_assert (wi::le_p (minv, maxv, sgn));
-      wi::to_mpz (minv, minc1, sgn);
-      wi::to_mpz (maxv, maxc1, sgn);
+      gcc_assert (wi::le_p (r.lower_bound (), r.upper_bound (), sgn));
+      wi::to_mpz (r.lower_bound (), minc1, sgn);
+      wi::to_mpz (r.upper_bound (), maxc1, sgn);
     }
   else
     {
@@ -372,34 +374,50 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
       gphi_iterator gsi;
 
       /* Either for VAR itself...  */
-      rtype = get_range_info (var, &minv, &maxv);
+      value_range var_range;
+      get_range_query (cfun)->range_of_expr (var_range, var);
+      rtype = var_range.kind ();
+      if (!var_range.undefined_p ())
+	{
+	  minv = var_range.lower_bound ();
+	  maxv = var_range.upper_bound ();
+	}
+
       /* Or for PHI results in loop->header where VAR is used as
 	 PHI argument from the loop preheader edge.  */
       for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi))
 	{
 	  gphi *phi = gsi.phi ();
-	  wide_int minc, maxc;
+	  value_range phi_range;
 	  if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var
-	      && (get_range_info (gimple_phi_result (phi), &minc, &maxc)
-		  == VR_RANGE))
+	      && get_range_query (cfun)->range_of_expr (phi_range,
+						    gimple_phi_result (phi))
+	      && phi_range.kind () == VR_RANGE)
 	    {
 	      if (rtype != VR_RANGE)
 		{
 		  rtype = VR_RANGE;
-		  minv = minc;
-		  maxv = maxc;
+		  minv = phi_range.lower_bound ();
+		  maxv = phi_range.upper_bound ();
 		}
 	      else
 		{
-		  minv = wi::max (minv, minc, sgn);
-		  maxv = wi::min (maxv, maxc, sgn);
+		  minv = wi::max (minv, phi_range.lower_bound (), sgn);
+		  maxv = wi::min (maxv, phi_range.upper_bound (), sgn);
 		  /* If the PHI result range are inconsistent with
 		     the VAR range, give up on looking at the PHI
 		     results.  This can happen if VR_UNDEFINED is
 		     involved.  */
 		  if (wi::gt_p (minv, maxv, sgn))
 		    {
-		      rtype = get_range_info (var, &minv, &maxv);
+		      value_range vr;
+		      get_range_query (cfun)->range_of_expr (vr, var);
+		      rtype = vr.kind ();
+		      if (!vr.undefined_p ())
+			{
+			  minv = vr.lower_bound ();
+			  maxv = vr.upper_bound ();
+			}
 		      break;
 		    }
 		}
@@ -3545,12 +3563,16 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
 
   if (tree_int_cst_sign_bit (step))
     {
-      wide_int min, max;
+      wide_int max;
+      value_range base_range;
+      if (get_range_query (cfun)->range_of_expr (base_range, orig_base)
+	  && !base_range.undefined_p ())
+	max = base_range.upper_bound ();
       extreme = fold_convert (unsigned_type, low);
       if (TREE_CODE (orig_base) == SSA_NAME
 	  && TREE_CODE (high) == INTEGER_CST
 	  && INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
-	  && (get_range_info (orig_base, &min, &max) == VR_RANGE
+	  && (base_range.kind () == VR_RANGE
 	      || get_cst_init_from_scev (orig_base, &max, false))
 	  && wi::gts_p (wi::to_wide (high), max))
 	base = wide_int_to_tree (unsigned_type, max);
@@ -3563,12 +3585,16 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
     }
   else
     {
-      wide_int min, max;
+      wide_int min;
+      value_range base_range;
+      if (get_range_query (cfun)->range_of_expr (base_range, orig_base)
+	  && !base_range.undefined_p ())
+	min = base_range.lower_bound ();
       extreme = fold_convert (unsigned_type, high);
       if (TREE_CODE (orig_base) == SSA_NAME
 	  && TREE_CODE (low) == INTEGER_CST
 	  && INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
-	  && (get_range_info (orig_base, &min, &max) == VR_RANGE
+	  && (base_range.kind () == VR_RANGE
 	      || get_cst_init_from_scev (orig_base, &min, true))
 	  && wi::gts_p (min, wi::to_wide (low)))
 	base = wide_int_to_tree (unsigned_type, min);
@@ -3835,11 +3861,12 @@ infer_loop_bounds_from_signedness (class loop *loop, gimple *stmt)
 
   low = lower_bound_in_type (type, type);
   high = upper_bound_in_type (type, type);
-  wide_int minv, maxv;
-  if (get_range_info (def, &minv, &maxv) == VR_RANGE)
+  value_range r;
+  get_range_query (cfun)->range_of_expr (r, def);
+  if (r.kind () == VR_RANGE)
     {
-      low = wide_int_to_tree (type, minv);
-      high = wide_int_to_tree (type, maxv);
+      low = wide_int_to_tree (type, r.lower_bound ());
+      high = wide_int_to_tree (type, r.upper_bound ());
     }
 
   record_nonwrapping_iv (loop, base, step, stmt, low, high, false, true);
@@ -4873,7 +4900,6 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
 {
   tree type;
   wide_int minv, maxv, diff, step_wi;
-  enum value_range_kind rtype;
 
   if (TREE_CODE (step) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (var)))
     return false;
@@ -4884,8 +4910,9 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
   if (!def_bb || !dominated_by_p (CDI_DOMINATORS, loop->latch, def_bb))
     return false;
 
-  rtype = get_range_info (var, &minv, &maxv);
-  if (rtype != VR_RANGE)
+  value_range r;
+  get_range_query (cfun)->range_of_expr (r, var);
+  if (r.kind () != VR_RANGE)
     return false;
 
   /* VAR is a scev whose evolution part is STEP and value range info
@@ -4899,11 +4926,11 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
   type = TREE_TYPE (var);
   if (tree_int_cst_sign_bit (step))
     {
-      diff = minv - wi::to_wide (lower_bound_in_type (type, type));
+      diff = r.lower_bound () - wi::to_wide (lower_bound_in_type (type, type));
       step_wi = - step_wi;
     }
   else
-    diff = wi::to_wide (upper_bound_in_type (type, type)) - maxv;
+    diff = wi::to_wide (upper_bound_in_type (type, type)) - r.upper_bound ();
 
   return (wi::geu_p (diff, step_wi));
 }
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
index 8e8a08bc679..17cebb018c7 100644
--- a/gcc/tree-ssa-phiopt.c
+++ b/gcc/tree-ssa-phiopt.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-eh.h"
 #include "gimple-fold.h"
 #include "internal-fn.h"
+#include "gimple-range.h"
 
 static unsigned int tree_ssa_phiopt_worker (bool, bool, bool);
 static bool two_value_replacement (basic_block, basic_block, edge, gphi *,
@@ -684,7 +685,15 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb,
     return false;
 
   wide_int min, max;
-  if (get_range_info (lhs, &min, &max) != VR_RANGE)
+  value_range r;
+  get_range_query (cfun)->range_of_expr (r, lhs);
+
+  if (r.kind () == VR_RANGE)
+    {
+      min = r.lower_bound ();
+      max = r.upper_bound ();
+    }
+  else
     {
       int prec = TYPE_PRECISION (TREE_TYPE (lhs));
       signop sgn = TYPE_SIGN (TREE_TYPE (lhs));
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index 2d22535af87..d86fe26bd07 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-dce.h"
 #include "tree-cfgcleanup.h"
 #include "alias.h"
+#include "gimple-range.h"
 
 /* Even though this file is called tree-ssa-pre.c, we actually
    implement a bit more than just PRE here.  All of them piggy-back
@@ -3234,16 +3235,18 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
 	  >= TYPE_PRECISION (TREE_TYPE (expr->u.nary->op[0])))
       && SSA_NAME_RANGE_INFO (expr->u.nary->op[0]))
     {
-      wide_int min, max;
-      if (get_range_info (expr->u.nary->op[0], &min, &max) == VR_RANGE
-	  && !wi::neg_p (min, SIGNED)
-	  && !wi::neg_p (max, SIGNED))
+      value_range r;
+      if (get_range_query (cfun)->range_of_expr (r, expr->u.nary->op[0])
+	  && r.kind () == VR_RANGE
+	  && !wi::neg_p (r.lower_bound (), SIGNED)
+	  && !wi::neg_p (r.upper_bound (), SIGNED))
 	/* Just handle extension and sign-changes of all-positive ranges.  */
-	set_range_info (temp,
-			SSA_NAME_RANGE_TYPE (expr->u.nary->op[0]),
-			wide_int_storage::from (min, TYPE_PRECISION (type),
+	set_range_info (temp, VR_RANGE,
+			wide_int_storage::from (r.lower_bound (),
+						TYPE_PRECISION (type),
 						TYPE_SIGN (type)),
-			wide_int_storage::from (max, TYPE_PRECISION (type),
+			wide_int_storage::from (r.upper_bound (),
+						TYPE_PRECISION (type),
 						TYPE_SIGN (type)));
     }
 
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 32e1632705b..6dfc70356d0 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "case-cfn-macros.h"
 #include "tree-ssa-reassoc.h"
 #include "tree-ssa-math-opts.h"
+#include "gimple-range.h"
 
 /*  This is a simple global reassociation pass.  It is, in part, based
     on the LLVM pass of the same name (They do some things more/less
@@ -3221,12 +3222,14 @@ optimize_range_tests_to_bit_test (enum tree_code opcode, int first, int length,
 	 amount, then we can merge the entry test in the bit test.  In this
 	 case, if we would need otherwise 2 or more comparisons, then use
 	 the bit test; in the other cases, the threshold is 3 comparisons.  */
-      wide_int min, max;
       bool entry_test_needed;
+      value_range r;
       if (TREE_CODE (exp) == SSA_NAME
-	  && get_range_info (exp, &min, &max) == VR_RANGE
-	  && wi::leu_p (max - min, prec - 1))
+	  && get_range_query (cfun)->range_of_expr (r, exp)
+	  && r.kind () == VR_RANGE
+	  && wi::leu_p (r.upper_bound () - r.lower_bound (), prec - 1))
 	{
+	  wide_int min = r.lower_bound ();
 	  wide_int ilowi = wi::to_wide (lowi);
 	  if (wi::lt_p (min, ilowi, TYPE_SIGN (TREE_TYPE (lowi))))
 	    {
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index c7b5e2c6e6b..423075b2bd1 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -196,7 +196,7 @@ static void handle_builtin_stxncpy_strncat (bool, gimple_stmt_iterator *);
 /* Sets MINMAX to either the constant value or the range VAL is in
    and returns either the constant value or VAL on success or null
    when the range couldn't be determined.  Uses RVALS when nonnull
-   to determine the range, otherwise get_range_info.  */
+   to determine the range, otherwise uses global range info.  */
 
 tree
 get_range (tree val, gimple *stmt, wide_int minmax[2],
@@ -211,9 +211,9 @@ get_range (tree val, gimple *stmt, wide_int minmax[2],
   if (TREE_CODE (val) != SSA_NAME)
     return NULL_TREE;
 
+  value_range vr;
   if (rvals && stmt)
     {
-      value_range vr;
       if (!rvals->range_of_expr (vr, val, stmt))
 	return NULL_TREE;
       value_range_kind rng = vr.kind ();
@@ -225,7 +225,15 @@ get_range (tree val, gimple *stmt, wide_int minmax[2],
       return val;
     }
 
-  value_range_kind rng = get_range_info (val, minmax, minmax + 1);
+  // ?? This entire function should use get_range_query or get_global_range_query (),
+  // instead of doing something different for RVALS and global ranges.
+
+  if (!get_global_range_query ()->range_of_expr (vr, val) || vr.undefined_p ())
+    return NULL_TREE;
+
+  minmax[0] = wi::to_wide (vr.min ());
+  minmax[1] = wi::to_wide (vr.max ());
+  value_range_kind rng = vr.kind ();
   if (rng == VR_RANGE)
     /* This may be an inverted range whose MINMAX[1] < MINMAX[0].  */
     return val;
@@ -929,7 +937,17 @@ dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals)
 			    rng = VR_UNDEFINED;
 			}
 		      else
-			rng = get_range_info (si->nonzero_chars, &min, &max);
+			{
+			  value_range vr;
+			  get_global_range_query ()->range_of_expr (vr,
+							     si->nonzero_chars);
+			  rng = vr.kind ();
+			  if (!vr.undefined_p ())
+			    {
+			      min = wi::to_wide (vr.min ());
+			      max = wi::to_wide (vr.max ());
+			    }
+			}
 
 		      if (rng == VR_RANGE || rng == VR_ANTI_RANGE)
 			{
@@ -1809,18 +1827,17 @@ set_strlen_range (tree lhs, wide_int min, wide_int max,
 	}
       else if (TREE_CODE (bound) == SSA_NAME)
 	{
-	  wide_int minbound, maxbound;
-	  // FIXME: Use range_query instead of global ranges.
-	  value_range_kind rng = get_range_info (bound, &minbound, &maxbound);
-	  if (rng == VR_RANGE)
+	  value_range r;
+	  get_range_query (cfun)->range_of_expr (r, bound);
+	  if (!r.undefined_p ())
 	    {
 	      /* For a bound in a known range, adjust the range determined
 		 above as necessary.  For a bound in some anti-range or
 		 in an unknown range, use the range determined by callers.  */
-	      if (wi::ltu_p (minbound, min))
-		min = minbound;
-	      if (wi::ltu_p (maxbound, max))
-		max = maxbound;
+	      if (wi::ltu_p (r.lower_bound (), min))
+		min = r.lower_bound ();
+	      if (wi::ltu_p (r.upper_bound (), max))
+		max = r.upper_bound ();
 	    }
 	}
     }
@@ -2780,12 +2797,15 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt,
     return false;
 
   wide_int cntrange[2];
+  value_range r;
+  if (!get_range_query (cfun)->range_of_expr (r, cnt)
+      || r.varying_p ()
+      || r.undefined_p ())
+    return false;
 
-  // FIXME: Use range_query instead of global ranges.
-  enum value_range_kind rng = get_range_info (cnt, cntrange, cntrange + 1);
-  if (rng == VR_RANGE)
-    ;
-  else if (rng == VR_ANTI_RANGE)
+  cntrange[0] = wi::to_wide (r.min ());
+  cntrange[1] = wi::to_wide (r.max ());
+  if (r.kind () == VR_ANTI_RANGE)
     {
       wide_int maxobjsize = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
 
@@ -2800,8 +2820,6 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt,
 	  cntrange[0] = wi::zero (TYPE_PRECISION (TREE_TYPE (cnt)));
 	}
     }
-  else
-    return false;
 
   /* Negative value is the constant string length.  If it's less than
      the lower bound there is no truncation.  Avoid calling get_stridx()
@@ -3923,13 +3941,12 @@ get_len_or_size (gimple *stmt, tree arg, int idx,
 	}
       else if (TREE_CODE (si->nonzero_chars) == SSA_NAME)
 	{
-	  wide_int min, max;
-	  // FIXME: Use range_query instead of global ranges.
-	  value_range_kind rng = get_range_info (si->nonzero_chars, &min, &max);
-	  if (rng == VR_RANGE)
+	  value_range r;
+	  get_range_query (cfun)->range_of_expr (r, si->nonzero_chars);
+	  if (r.kind () == VR_RANGE)
 	    {
-	      lenrng[0] = min.to_uhwi ();
-	      lenrng[1] = max.to_uhwi ();
+	      lenrng[0] = r.lower_bound ().to_uhwi ();
+	      lenrng[1] = r.upper_bound ().to_uhwi ();
 	      *nulterm = si->full_string_p;
 	    }
 	}
@@ -5301,17 +5318,13 @@ handle_integral_assign (gimple_stmt_iterator *gsi, bool *cleanup_eh,
 		  /* Reading a character before the final '\0'
 		     character.  Just set the value range to ~[0, 0]
 		     if we don't have anything better.  */
-		  wide_int min, max;
-		  signop sign = TYPE_SIGN (lhs_type);
-		  int prec = TYPE_PRECISION (lhs_type);
-		  // FIXME: Use range_query instead of global ranges.
-		  value_range_kind vr = get_range_info (lhs, &min, &max);
-		  if (vr == VR_VARYING
-		      || (vr == VR_RANGE
-			  && min == wi::min_value (prec, sign)
-			  && max == wi::max_value (prec, sign)))
-		    set_range_info (lhs, VR_ANTI_RANGE,
-				    wi::zero (prec), wi::zero (prec));
+		  value_range r;
+		  if (!get_range_query (cfun)->range_of_expr (r, lhs)
+		      || r.varying_p ())
+		    {
+		      r.set_nonzero (lhs_type);
+		      set_range_info (lhs, r);
+		    }
 		}
 	    }
 	}
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index a0238710e72..7163438e23d 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -43,6 +43,7 @@
 #include "attribs.h"
 #include "tree-ssa.h"
 #include "tree-cfg.h"
+#include "gimple-range.h"
 
 /* The idea behind this analyzer is to generate set constraints from the
    program, then solve the resulting constraints in order to generate the
@@ -6740,7 +6741,9 @@ find_what_p_points_to (tree fndecl, tree p)
   struct ptr_info_def *pi;
   tree lookup_p = p;
   varinfo_t vi;
-  bool nonnull = get_ptr_nonnull (p);
+  value_range vr;
+  get_range_query (DECL_STRUCT_FUNCTION (fndecl))->range_of_expr (vr, p);
+  bool nonnull = vr.nonzero_p ();
 
   /* For parameters, get at the points-to set for the actual parm
      decl.  */
@@ -6758,8 +6761,7 @@ find_what_p_points_to (tree fndecl, tree p)
   pi->pt = find_what_var_points_to (fndecl, vi);
   /* Conservatively set to NULL from PTA (to true). */
   pi->pt.null = 1;
-  /* Preserve pointer nonnull computed by VRP.  See get_ptr_nonnull
-     in gcc/tree-ssaname.c for more information.  */
+  /* Preserve pointer nonnull globally computed.  */
   if (nonnull)
     set_ptr_nonnull (p);
 }
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index f55ce1939ac..dcfdec96881 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "builtins.h"
 #include "calls.h"
+#include "gimple-range.h"
 
 /* This implements the pass that does predicate aware warning on uses of
    possibly uninitialized variables.  The pass first collects the set of
@@ -1606,11 +1607,14 @@ find_var_cmp_const (pred_chain_union preds, gphi *phi, gimple **flag_def,
 	       flag_var <= [min, max] ->  flag_var < [min, max+1]
 	       flag_var >= [min, max] ->  flag_var > [min-1, max]
 	     if no overflow/wrap.  */
-	  wide_int min, max;
 	  tree type = TREE_TYPE (cond_lhs);
+	  value_range r;
 	  if (!INTEGRAL_TYPE_P (type)
-	      || get_range_info (cond_rhs, &min, &max) != VR_RANGE)
+	      || !get_range_query (cfun)->range_of_expr (r, cond_rhs)
+	      || r.kind () != VR_RANGE)
 	    continue;
+	  wide_int min = r.lower_bound ();
+	  wide_int max = r.upper_bound ();
 	  if (code == LE_EXPR
 	      && max != wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)))
 	    {
diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
index 7f65c4ce839..294b5457008 100644
--- a/gcc/tree-switch-conversion.c
+++ b/gcc/tree-switch-conversion.c
@@ -50,6 +50,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "target.h"
 #include "tree-into-ssa.h"
 #include "omp-general.h"
+#include "gimple-range.h"
 
 /* ??? For lang_hooks.types.type_for_mode, but is there a word_mode
    type in the GIMPLE type system that is language-independent?  */
@@ -1553,12 +1554,15 @@ bit_test_cluster::emit (tree index_expr, tree index_type,
 
   /* If every possible relative value of the index expression is a valid shift
      amount, then we can merge the entry test in the bit test.  */
-  wide_int min, max;
   bool entry_test_needed;
+  value_range r;
   if (TREE_CODE (index_expr) == SSA_NAME
-      && get_range_info (index_expr, &min, &max) == VR_RANGE
-      && wi::leu_p (max - min, prec - 1))
+      && get_range_query (cfun)->range_of_expr (r, index_expr)
+      && r.kind () == VR_RANGE
+      && wi::leu_p (r.upper_bound () - r.lower_bound (), prec - 1))
     {
+      wide_int min = r.lower_bound ();
+      wide_int max = r.upper_bound ();
       tree index_type = TREE_TYPE (index_expr);
       minval = fold_convert (index_type, minval);
       wide_int iminval = wi::to_wide (minval);
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index 803de3fc287..177d44ebb5e 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "predict.h"
 #include "tree-vector-builder.h"
 #include "vec-perm-indices.h"
+#include "gimple-range.h"
 
 /* Return true if we have a useful VR_RANGE range for VAR, storing it
    in *MIN_VALUE and *MAX_VALUE if so.  Note the range in the dump files.  */
@@ -55,7 +56,13 @@ along with GCC; see the file COPYING3.  If not see
 static bool
 vect_get_range_info (tree var, wide_int *min_value, wide_int *max_value)
 {
-  value_range_kind vr_type = get_range_info (var, min_value, max_value);
+  value_range vr;
+  get_range_query (cfun)->range_of_expr (vr, var);
+  if (vr.undefined_p ())
+    vr.set_varying (TREE_TYPE (var));
+  *min_value = wi::to_wide (vr.min ());
+  *max_value = wi::to_wide (vr.max ());
+  value_range_kind vr_type = vr.kind ();
   wide_int nonzero = get_nonzero_bits (var);
   signop sgn = TYPE_SIGN (TREE_TYPE (var));
   if (intersect_range_with_nonzero_bits (vr_type, min_value, max_value,
@@ -3437,13 +3444,14 @@ vect_recog_divmod_pattern (vec_info *vinfo,
       else
 	t3 = t2;
 
-      wide_int oprnd0_min, oprnd0_max;
       int msb = 1;
-      if (get_range_info (oprnd0, &oprnd0_min, &oprnd0_max) == VR_RANGE)
+      value_range r;
+      get_range_query (cfun)->range_of_expr (r, oprnd0);
+      if (r.kind () == VR_RANGE)
 	{
-	  if (!wi::neg_p (oprnd0_min, TYPE_SIGN (itype)))
+	  if (!wi::neg_p (r.lower_bound (), TYPE_SIGN (itype)))
 	    msb = 0;
-	  else if (wi::neg_p (oprnd0_max, TYPE_SIGN (itype)))
+	  else if (wi::neg_p (r.upper_bound (), TYPE_SIGN (itype)))
 	    msb = -1;
 	}
 
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index b0f1c47f05c..450926d5f9b 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -228,7 +228,7 @@ intersect_range_with_nonzero_bits (enum value_range_kind vr_type,
 	  vr_type = VR_RANGE;
 	}
     }
-  if (vr_type == VR_RANGE)
+  if (vr_type == VR_RANGE || vr_type == VR_VARYING)
     {
       *max = wi::round_down_for_mask (*max, nonzero_bits);
 
@@ -1717,7 +1717,7 @@ register_edge_assert_for_2 (tree name, edge e,
          simply register the same assert for it.  */
       if (CONVERT_EXPR_CODE_P (rhs_code))
 	{
-	  wide_int rmin, rmax;
+	  value_range vr;
 	  tree rhs1 = gimple_assign_rhs1 (def_stmt);
 	  if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
 	      && TREE_CODE (rhs1) == SSA_NAME
@@ -1739,13 +1739,14 @@ register_edge_assert_for_2 (tree name, edge e,
 	      && int_fits_type_p (val, TREE_TYPE (rhs1))
 	      && ((TYPE_PRECISION (TREE_TYPE (name))
 		   > TYPE_PRECISION (TREE_TYPE (rhs1)))
-		  || (get_range_info (rhs1, &rmin, &rmax) == VR_RANGE
+		  || ((get_range_query (cfun)->range_of_expr (vr, rhs1)
+		       && vr.kind () == VR_RANGE)
 		      && wi::fits_to_tree_p
-			   (widest_int::from (rmin,
+			   (widest_int::from (vr.lower_bound (),
 					      TYPE_SIGN (TREE_TYPE (rhs1))),
 			    TREE_TYPE (name))
 		      && wi::fits_to_tree_p
-			   (widest_int::from (rmax,
+			   (widest_int::from (vr.upper_bound (),
 					      TYPE_SIGN (TREE_TYPE (rhs1))),
 			    TREE_TYPE (name)))))
 	    add_assert_info (asserts, rhs1, rhs1,
@@ -4631,16 +4632,14 @@ determine_value_range_1 (value_range *vr, tree expr)
     vr->set (expr);
   else
     {
-      value_range_kind kind;
-      wide_int min, max;
+      value_range r;
       /* For SSA names try to extract range info computed by VRP.  Otherwise
 	 fall back to varying.  */
       if (TREE_CODE (expr) == SSA_NAME
 	  && INTEGRAL_TYPE_P (TREE_TYPE (expr))
-	  && (kind = get_range_info (expr, &min, &max)) != VR_VARYING)
-	vr->set (wide_int_to_tree (TREE_TYPE (expr), min),
-		 wide_int_to_tree (TREE_TYPE (expr), max),
-		 kind);
+	  && get_range_query (cfun)->range_of_expr (r, expr)
+	  && !r.undefined_p ())
+	*vr = r;
       else
 	vr->set_varying (TREE_TYPE (expr));
     }
diff --git a/gcc/tree.c b/gcc/tree.c
index 31ac4245c9c..24fb7f571ab 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -68,6 +68,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vector-builder.h"
 #include "gimple-fold.h"
 #include "escaped_string.h"
+#include "gimple-range.h"
 
 /* Tree code classes.  */
 
@@ -13834,8 +13835,8 @@ get_range_pos_neg (tree arg)
 
   if (TREE_CODE (arg) != SSA_NAME)
     return 3;
-  wide_int arg_min, arg_max;
-  while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE)
+  value_range r;
+  while (!get_global_range_query ()->range_of_expr (r, arg) || r.kind () != VR_RANGE)
     {
       gimple *g = SSA_NAME_DEF_STMT (arg);
       if (is_gimple_assign (g)
@@ -13861,16 +13862,16 @@ get_range_pos_neg (tree arg)
     {
       /* For unsigned values, the "positive" range comes
 	 below the "negative" range.  */
-      if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED))
+      if (!wi::neg_p (wi::sext (r.upper_bound (), prec), SIGNED))
 	return 1;
-      if (wi::neg_p (wi::sext (arg_min, prec), SIGNED))
+      if (wi::neg_p (wi::sext (r.lower_bound (), prec), SIGNED))
 	return 2;
     }
   else
     {
-      if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED))
+      if (!wi::neg_p (wi::sext (r.lower_bound (), prec), SIGNED))
 	return 1;
-      if (wi::neg_p (wi::sext (arg_max, prec), SIGNED))
+      if (wi::neg_p (wi::sext (r.upper_bound (), prec), SIGNED))
 	return 2;
     }
   return 3;
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index a89f0b646ae..ff97997c9df 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -117,14 +117,16 @@ vr_values::get_lattice_entry (const_tree var)
 	     default definitions of PARM_DECLs.  */
 	  if (POINTER_TYPE_P (TREE_TYPE (sym))
 	      && (nonnull_arg_p (sym)
-		  || get_ptr_nonnull (var)))
+		  || (get_global_range_query ()->range_of_expr (*vr,
+						const_cast <tree> (var))
+		      && vr->nonzero_p ())))
 	    {
 	      vr->set_nonzero (TREE_TYPE (sym));
 	      vr->equiv_clear ();
 	    }
 	  else if (INTEGRAL_TYPE_P (TREE_TYPE (sym)))
 	    {
-	      get_range_info (var, *vr);
+	      get_global_range_query ()->range_of_expr (*vr, const_cast <tree> (var));
 	      if (vr->undefined_p ())
 		vr->set_varying (TREE_TYPE (sym));
 	    }
@@ -262,7 +264,7 @@ vr_values::update_value_range (const_tree var, value_range_equiv *new_vr)
   if (INTEGRAL_TYPE_P (TREE_TYPE (var)))
     {
       value_range_equiv nr;
-      get_range_info (var, nr);
+      get_global_range_query ()->range_of_expr (nr, const_cast <tree> (var));
       if (!nr.undefined_p ())
 	new_vr->intersect (&nr);
     }
@@ -3829,13 +3831,13 @@ simplify_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
       || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop))
     return false;
 
-  /* Get the value-range of the inner operand.  Use get_range_info in
+  /* Get the value-range of the inner operand.  Use global ranges in
      case innerop was created during substitute-and-fold.  */
   wide_int imin, imax;
   value_range vr;
   if (!INTEGRAL_TYPE_P (TREE_TYPE (innerop)))
     return false;
-  get_range_info (innerop, vr);
+  get_range_query (cfun)->range_of_expr (vr, innerop, stmt);
   if (vr.undefined_p () || vr.varying_p ())
     return false;
   innermin = widest_int::from (vr.lower_bound (), TYPE_SIGN (TREE_TYPE (innerop)));
-- 
2.31.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 5/5] Cleanup get_range_info
  2021-05-21 11:39 ` [PATCH 5/5] Cleanup get_range_info Aldy Hernandez
@ 2021-05-25 16:20   ` Aldy Hernandez
  0 siblings, 0 replies; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-25 16:20 UTC (permalink / raw)
  To: GCC patches, Andrew MacLeod; +Cc: Jeff Law, Martin Sebor

No changes needed for this patch.

OK pending tests?

Aldy


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun).
  2021-05-25 16:17   ` Aldy Hernandez
@ 2021-05-25 16:28     ` Jeff Law
  2021-05-25 17:28     ` Martin Sebor
  2021-05-27  7:38     ` Christophe Lyon
  2 siblings, 0 replies; 31+ messages in thread
From: Jeff Law @ 2021-05-25 16:28 UTC (permalink / raw)
  To: Aldy Hernandez, GCC patches, Andrew MacLeod; +Cc: Martin Sebor



On 5/25/2021 10:17 AM, Aldy Hernandez wrote:
> Adjustments per discussion.
>
> OK pending tests?
The latest revision of #2-#5 are OK once #1 is ACK'd.



Jeff



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun).
  2021-05-25 16:17   ` Aldy Hernandez
  2021-05-25 16:28     ` Jeff Law
@ 2021-05-25 17:28     ` Martin Sebor
  2021-05-27  7:38     ` Christophe Lyon
  2 siblings, 0 replies; 31+ messages in thread
From: Martin Sebor @ 2021-05-25 17:28 UTC (permalink / raw)
  To: Aldy Hernandez, GCC patches, Andrew MacLeod; +Cc: Martin Sebor

On 5/25/21 10:17 AM, Aldy Hernandez via Gcc-patches wrote:
> Adjustments per discussion.
> 
> OK pending tests?
> 
> Aldy

I have no concern with the alloca changes.  The xfail removals from
the two tests in this patch (a nice improvement) don't seem to be
related to alloca so I'd expect them to fail unless the strlen changes
are committed first.

Martin

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] Common API for accessing global and on-demand ranges.
  2021-05-25 16:16             ` Aldy Hernandez
@ 2021-05-26 13:40               ` Andrew MacLeod
  2021-05-29  4:35               ` Jeff Law
  1 sibling, 0 replies; 31+ messages in thread
From: Andrew MacLeod @ 2021-05-26 13:40 UTC (permalink / raw)
  To: Aldy Hernandez, Richard Biener; +Cc: GCC patches, Martin Sebor

On 5/25/21 12:16 PM, Aldy Hernandez wrote:
> The interface is now an inline function for get_range_query() and an 
> external function for get_global_range_query), as discussed.
>
> There are no magic cfun uses behind the scenes.
>
> The annoying downcast is gone.
>
> Passes can now decide if they want to export global ranges after they 
> use a ranger.
>
> I've adjusted the ChangeLog entries, as well as the commit text.
>
> I've addressed everything discussed.
>
> OK pending tests?
>
> Aldy

There doesn't seem to be any disagreement..   OK.   Any further 
refinements that come up we can adjust.

Andrew


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/5] Convert evrp pass to RANGE_QUERY(cfun).
  2021-05-25 16:18   ` Aldy Hernandez
@ 2021-05-27  2:34     ` H.J. Lu
  0 siblings, 0 replies; 31+ messages in thread
From: H.J. Lu @ 2021-05-27  2:34 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: GCC patches, Andrew MacLeod, Martin Sebor

On Tue, May 25, 2021 at 10:15 AM Aldy Hernandez via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> Adjustments per discussion.
>
> OK pending tests?
>
> Aldy

This caused:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100787

-- 
H.J.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun).
  2021-05-25 16:17   ` Aldy Hernandez
  2021-05-25 16:28     ` Jeff Law
  2021-05-25 17:28     ` Martin Sebor
@ 2021-05-27  7:38     ` Christophe Lyon
  2021-05-27  8:34       ` Aldy Hernandez
  2 siblings, 1 reply; 31+ messages in thread
From: Christophe Lyon @ 2021-05-27  7:38 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: GCC patches, Andrew MacLeod, Martin Sebor

Hi,

On Tue, 25 May 2021 at 18:17, Aldy Hernandez via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> Adjustments per discussion.
>
> OK pending tests?
>

The xfail removal causes failures on 32 bits platforms (eg arm, or
aarch64 with -mabi=ilp32):
FAIL: gcc.dg/Wstringop-overflow-55.c pr????? (test for warnings, line 86)
FAIL: gcc.dg/Wstringop-overflow-55.c pr????? (test for warnings, line 94)


Christophe

> Aldy

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun).
  2021-05-27  7:38     ` Christophe Lyon
@ 2021-05-27  8:34       ` Aldy Hernandez
  0 siblings, 0 replies; 31+ messages in thread
From: Aldy Hernandez @ 2021-05-27  8:34 UTC (permalink / raw)
  To: Christophe Lyon; +Cc: GCC patches, Andrew MacLeod, Martin Sebor

[-- Attachment #1: Type: text/plain, Size: 902 bytes --]

On x86-32 warn_ptrdiff_anti_range_add() and warn_int_anti_range()
degrade to the same function so ICF is folding the latter into a call
into the former.  This is causing no warnings to be emitted for
warn_int_anti_range.

Fixed by passing -fno-ipa-icf to the test.

Long term, we really should be finding a way to run these warning
passes earlier :-/.

Pushed.

On Thu, May 27, 2021 at 9:39 AM Christophe Lyon
<christophe.lyon@linaro.org> wrote:
>
> Hi,
>
> On Tue, 25 May 2021 at 18:17, Aldy Hernandez via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
> >
> > Adjustments per discussion.
> >
> > OK pending tests?
> >
>
> The xfail removal causes failures on 32 bits platforms (eg arm, or
> aarch64 with -mabi=ilp32):
> FAIL: gcc.dg/Wstringop-overflow-55.c pr????? (test for warnings, line 86)
> FAIL: gcc.dg/Wstringop-overflow-55.c pr????? (test for warnings, line 94)
>
>
> Christophe
>
> > Aldy
>

[-- Attachment #2: 0001-Tweak-Wstringop-overflow-55.c-test.patch --]
[-- Type: text/x-patch, Size: 1207 bytes --]

From 95bef94c6c6c6cb7bf640068aea77c209bca7c65 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Thu, 27 May 2021 09:32:42 +0200
Subject: [PATCH] Tweak Wstringop-overflow-55.c test.

On x86-32 warn_ptrdiff_anti_range_add() and warn_int_anti_range()
degrade to the same function so ICF is folding the latter into a call
into the former.  This is causing no warnings to be emitted for
warn_int_anti_range.

Fixed by passing -fno-ipa-icf.

gcc/testsuite/ChangeLog:

	* gcc.dg/Wstringop-overflow-55.c: Pass -fno-ipa-icf.
---
 gcc/testsuite/gcc.dg/Wstringop-overflow-55.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c
index 8df5cb629ae..c3c2dbe06dd 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c
@@ -1,6 +1,6 @@
 /* Verify that offsets in "anti-ranges" are handled correctly.
    { dg-do compile }
-   { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+   { dg-options "-O2 -Wall -ftrack-macro-expansion=0 -fno-ipa-icf" } */
 
 typedef __PTRDIFF_TYPE__ ptrdiff_t;
 typedef __SIZE_TYPE__    size_t;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 1/5] Common API for accessing global and on-demand ranges.
  2021-05-25 16:16             ` Aldy Hernandez
  2021-05-26 13:40               ` Andrew MacLeod
@ 2021-05-29  4:35               ` Jeff Law
  1 sibling, 0 replies; 31+ messages in thread
From: Jeff Law @ 2021-05-29  4:35 UTC (permalink / raw)
  To: Aldy Hernandez, Richard Biener; +Cc: Martin Sebor, GCC patches



On 5/25/2021 10:16 AM, Aldy Hernandez via Gcc-patches wrote:
> The interface is now an inline function for get_range_query() and an 
> external function for get_global_range_query), as discussed.
>
> There are no magic cfun uses behind the scenes.
>
> The annoying downcast is gone.
>
> Passes can now decide if they want to export global ranges after they 
> use a ranger.
>
> I've adjusted the ChangeLog entries, as well as the commit text.
>
> I've addressed everything discussed.
>
> OK pending tests?
>
> Aldy
>
> 0001-Common-API-for-accessing-global-and-on-demand-ranges.patch
>
>  From eeb7627ddf686d5affb08dcad3674b560ef3ce6d Mon Sep 17 00:00:00 2001
> From: Aldy Hernandez <aldyh@redhat.com>
> Date: Wed, 19 May 2021 18:27:05 +0200
> Subject: [PATCH 1/5] 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.
OK
jeff


^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2021-05-29  4:35 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-21 11:39 [PATCH 1/5] Common API for accessing global and on-demand ranges Aldy Hernandez
2021-05-21 11:39 ` [PATCH 2/5] Convert Walloca pass to RANGE_QUERY(cfun) Aldy Hernandez
2021-05-25  8:43   ` Richard Biener
2021-05-25 16:17   ` Aldy Hernandez
2021-05-25 16:28     ` Jeff Law
2021-05-25 17:28     ` Martin Sebor
2021-05-27  7:38     ` Christophe Lyon
2021-05-27  8:34       ` Aldy Hernandez
2021-05-21 11:39 ` [PATCH 3/5] Convert evrp " Aldy Hernandez
2021-05-25 16:18   ` Aldy Hernandez
2021-05-27  2:34     ` H.J. Lu
2021-05-21 11:39 ` [PATCH 4/5] Convert remaining passes to RANGE_QUERY Aldy Hernandez
2021-05-24 19:34   ` Martin Sebor
2021-05-25  8:47     ` Richard Biener
2021-05-25  9:15       ` Aldy Hernandez
2021-05-25 11:26       ` Aldy Hernandez
2021-05-25  8:48     ` Aldy Hernandez
2021-05-25 16:19   ` Aldy Hernandez
2021-05-21 11:39 ` [PATCH 5/5] Cleanup get_range_info Aldy Hernandez
2021-05-25 16:20   ` Aldy Hernandez
2021-05-24 16:09 ` [PATCH 1/5] Common API for accessing global and on-demand ranges Aldy Hernandez
2021-05-25  8:57   ` Richard Biener
2021-05-25  9:36     ` Aldy Hernandez
2021-05-25  9:46       ` Richard Biener
2021-05-25 10:53         ` Aldy Hernandez
2021-05-25 11:06           ` Richard Biener
2021-05-25 16:16             ` Aldy Hernandez
2021-05-26 13:40               ` Andrew MacLeod
2021-05-29  4:35               ` Jeff Law
2021-05-24 19:13 ` Martin Sebor
2021-05-25  7:06   ` Aldy Hernandez

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).