public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] generalized range_query class for multiple contexts
@ 2020-09-18 18:38 Aldy Hernandez
  2020-09-18 20:40 ` Aldy Hernandez
                   ` (2 more replies)
  0 siblings, 3 replies; 26+ messages in thread
From: Aldy Hernandez @ 2020-09-18 18:38 UTC (permalink / raw)
  To: gcc-patches

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

As part of the ranger work, we have been trying to clean up and 
generalize interfaces whenever possible.  This not only helps in 
reducing the maintenance burden going forward, but provides mechanisms 
for backwards compatibility between ranger and other providers/users of 
ranges throughout the compiler like evrp and VRP.

One such interface is the range_query class in vr_values.h, which 
provides a range query mechanism for use in the simplify_using_ranges 
module.  With it, simplify_using_ranges can be used with the ranger, or 
the VRP twins by providing a get_value_range() method.  This has helped 
us in comparing apples to apples while doing our work, and has also 
future proofed the interface so that asking for a range can be done 
within the context in which it appeared.  For example, get_value_range 
now takes a gimple statement which provides context.  We are no longer 
tied to asking for a global SSA range, but can ask for the range of an 
SSA within a statement.  Granted, this functionality is currently only 
in the ranger, but evrp/vrp could be adapted to pass such context.

The range_query is a good first step, but what we really want is a 
generic query mechanism that can ask for SSA ranges within an 
expression, a statement, an edge, or anything else that may come up.  We 
think that a generic mechanism can be used not only for range producers, 
but consumers such as the substitute_and_fold_engine (see get_value 
virtual) and possibly the gimple folder (see valueize).

The attached patchset provides such an interface.  It is meant to be a 
replacement for range_query that can be used for vr_values, 
substitute_and_fold, the subsitute_and_fold_engine, as well as the 
ranger.  The general API is:

class value_query
{
public:
   // Return the singleton expression for NAME at a gimple statement,
   // or NULL if none found.
   virtual tree value_of_expr (tree name, gimple * = NULL) = 0;
   // Return the singleton expression for NAME at an edge, or NULL if
   // none found.
   virtual tree value_on_edge (edge, tree name);
   // Return the singleton expression for the LHS of a gimple
   // statement, assuming an (optional) initial value of NAME.  Returns
   // NULL if none found.
   //
   // Note this method calculates the range the LHS would have *after*
   // the statement has executed.
   virtual tree value_of_stmt (gimple *, tree name = NULL);
};

class range_query : public value_query
{
public:
   range_query ();
   virtual ~range_query ();

   virtual tree value_of_expr (tree name, gimple * = NULL) OVERRIDE;
   virtual tree value_on_edge (edge, tree name) OVERRIDE;
   virtual tree value_of_stmt (gimple *, tree name = NULL) OVERRIDE;

   // These are the range equivalents of the value_* methods.  Instead
   // of returning a singleton, they calculate a range and return it in
   // R.  TRUE is returned on success or FALSE if no range was found.
   virtual bool range_of_expr (irange &r, tree name, gimple * = NULL) = 0;
   virtual bool range_on_edge (irange &r, edge, tree name);
   virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL);

   // DEPRECATED: This method is used from vr-values.  The plan is to
   // rewrite all uses of it to the above API.
   virtual const class value_range_equiv *get_value_range (const_tree,
							  gimple * = NULL);
};

The duality of the API (value_of_* and range_on_*) is because some 
passes are interested in a singleton value 
(substitute_and_fold_enginge), while others are interested in ranges 
(vr_values).  Passes that are only interested in singletons can take a 
value_query, while passes that are interested in full ranges, can take a 
range_query.  Of course, for future proofing, we would recommend taking 
a range_query, since if you provide a default range_of_expr, sensible 
defaults will be provided for the others in terms of range_of_expr.

Note, that the absolute bare minimum that must be provided is a 
value_of_expr and a range_of_expr respectively.

One piece of the API which is missing is a method  to return the range 
of an arbitrary SSA_NAME *after* a statement.  Currently range_of_expr 
calculates the range of an expression upon entry to the statement, 
whereas range_of_stmt calculates the range of *only* the LHS of a 
statement AFTER the statement has executed.

This would allow for complete representation of the ranges/values in 
something like:

     d_4 = *g_7;

Here the range of g_7 upon entry could be VARYING, but after the 
dereference we know it must be non-zero.  Well for sane targets anyhow.

Choices would be to:

   1) add a 4th method such as "range_after_stmt", or

   2) merge that functionality with the existing range_of_stmt method to 
provide "after" functionality for any ssa_name.  Currently the SSA_NAME 
must be the same as the LHS if specified.  It also does not need to be 
specified to allow evaluation of statements without a LHS, (if (x < 1) 
has no LHS, but will return [0,0] [1,1] or [0,1] as there is a boolean 
"result" to the statement.

Also, we've debated whether to use the two classes (value_query and 
range_query) separately as above, or perhaps join them into one class. 
I personally like the separation of powers.  Some users only care for 
singletons, no sense in polluting their implementations with talk of 
ranges.  But we're open to suggestions.

The patchset is divided into 3 parts:

1. Generic implementation of class.

2. Conversion of vr_values and substitute_and_fold_engine to class.

The conversion of the substitute_and_fold_engine class involved changing 
all calls to get_value() to a corresponding method providing context. 
For example, when the edge or statement is available, we pass these to 
the appropriate method.

With this, we've been able to plug in the ranger into our hybrid evrp, 
which can then get better ranges.  Our hybrid evrp has moved a lot of 
optimizations that were happening much later into the early vrp stage.

3. Conversion of sprintf/strlen pass to class.

This is a nonfunctional change to the sprintf/strlen passes.  That is, 
no effort was made to change the passes to multi-ranges.  However, with 
this patch, we are able to plug in a ranger or evrp with just a few 
lines, since the range query mechanism share a common API.

---------------------

We think this interface is generic enough to be used in any place that 
queries ranges or singletons, basically any place we have *valueize* in 
the compiler.  It can also be used to replace range generators at will, 
or even combine them to get the best of both worlds.  For example, 
places that currently have a value_* interface because they work with 
constants, like CCP, could have an alternate valueizer plugged in and if 
a range folds to a constant, CCP could then propagate that constant.

Tested on x86-64 Linux.

Aldy

[-- Attachment #2: 0001-Initial-implementation-of-value-query-class.patch --]
[-- Type: text/x-patch, Size: 8696 bytes --]

From d8a68df9eac61920452afa11686829dd469bcd16 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Thu, 17 Sep 2020 09:23:12 +0200
Subject: [PATCH 1/3] Initial implementation of value query class.

---
 gcc/Makefile.in    |   1 +
 gcc/value-query.cc | 161 +++++++++++++++++++++++++++++++++++++++++++++
 gcc/value-query.h  |  97 +++++++++++++++++++++++++++
 3 files changed, 259 insertions(+)
 create mode 100644 gcc/value-query.cc
 create mode 100644 gcc/value-query.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 79e854aa938..9bc568fa9fd 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1644,6 +1644,7 @@ OBJS = \
 	typed-splay-tree.o \
 	unique-ptr-tests.o \
 	valtrack.o \
+	value-query.o \
 	value-range.o \
 	value-range-equiv.o \
 	value-prof.o \
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
new file mode 100644
index 00000000000..7afa1ae5250
--- /dev/null
+++ b/gcc/value-query.cc
@@ -0,0 +1,161 @@
+/* Support routines for value queries.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez <aldyh@redhat.com> and
+   Andrew MacLeod <amacleod@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "ssa.h"
+#include "tree-pretty-print.h"
+#include "fold-const.h"
+#include "value-range-equiv.h"
+#include "value-query.h"
+#include "alloc-pool.h"
+
+// value_query default methods.
+
+tree
+value_query::value_on_edge (edge, tree name)
+{
+  return value_of_expr (name);
+}
+
+tree
+value_query::value_of_stmt (gimple *stmt, tree name)
+{
+  if (!name)
+    name = gimple_get_lhs (stmt);
+
+  gcc_checking_assert (!name || name == gimple_get_lhs (stmt));
+
+  if (name)
+    return value_of_expr (name);
+  return NULL_TREE;
+}
+
+// range_query default methods.
+
+bool
+range_query::range_on_edge (irange &r, edge, tree name)
+{
+  return range_of_expr (r, name);
+}
+
+bool
+range_query::range_of_stmt (irange &r, gimple *stmt, tree name)
+{
+  if (!name)
+    name = gimple_get_lhs (stmt);
+
+  gcc_checking_assert (!name || name == gimple_get_lhs (stmt));
+
+  if (name)
+    return range_of_expr (r, name);
+  return false;
+}
+
+tree
+range_query::value_of_expr (tree name, gimple *stmt)
+{
+  tree t;
+  value_range r;
+
+  if (!irange::supports_type_p (TREE_TYPE (name)))
+    return NULL_TREE;
+  if (range_of_expr (r, name, stmt) && r.singleton_p (&t))
+    return t;
+  return NULL_TREE;
+}
+
+tree
+range_query::value_on_edge (edge e, tree name)
+{
+  tree t;
+  value_range r;
+
+  if (!irange::supports_type_p (TREE_TYPE (name)))
+    return NULL_TREE;
+  if (range_on_edge (r, e, name) && r.singleton_p (&t))
+    return t;
+  return NULL_TREE;
+
+}
+
+tree
+range_query::value_of_stmt (gimple *stmt, tree name)
+{
+  tree t;
+  value_range r;
+
+  if (!name)
+    name = gimple_get_lhs (stmt);
+
+  gcc_checking_assert (!name || name == gimple_get_lhs (stmt));
+
+  if (!name || !irange::supports_type_p (TREE_TYPE (name)))
+    return NULL_TREE;
+  if (range_of_stmt (r, stmt, name) && r.singleton_p (&t))
+    return t;
+  return NULL_TREE;
+
+}
+
+// valuation_query support routines for value_range_equiv's.
+
+class equiv_allocator : public object_allocator<value_range_equiv>
+{
+public:
+  equiv_allocator ()
+    : object_allocator<value_range_equiv> ("equiv_allocator pool") { }
+};
+
+value_range_equiv *
+range_query::allocate_value_range_equiv ()
+{
+  return new (equiv_alloc->allocate ()) value_range_equiv;
+}
+
+void
+range_query::free_value_range_equiv (value_range_equiv *v)
+{
+  equiv_alloc->remove (v);
+}
+
+const class value_range_equiv *
+range_query::get_value_range (const_tree expr, gimple *stmt)
+{
+  int_range_max r;
+  if (range_of_expr (r, const_cast<tree> (expr), stmt))
+    return new (equiv_alloc->allocate ()) value_range_equiv (r);
+  return new (equiv_alloc->allocate ()) value_range_equiv (TREE_TYPE (expr));
+}
+
+range_query::range_query ()
+{
+  equiv_alloc = new equiv_allocator;
+}
+
+range_query::~range_query ()
+{
+  equiv_alloc->release ();
+}
diff --git a/gcc/value-query.h b/gcc/value-query.h
new file mode 100644
index 00000000000..a64e37d7596
--- /dev/null
+++ b/gcc/value-query.h
@@ -0,0 +1,97 @@
+/* Support routines for value queries.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez <aldyh@redhat.com> and
+   Andrew Macleod <amacleod@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_QUERY_H
+#define GCC_QUERY_H
+
+// value_query is used by optimization passes that require valueizing
+// ssa_names in terms of a tree value, but have no neeed for ranges.
+//
+// value_of_expr is required to be provided.
+// value_on_edge and value_of_stmt default to simply calling value_of_expr.
+//
+// This implies the valuation is global in nature.  If a pass can make use
+// of more specific information, then it can override the other queries.
+//
+// Proper usage of the correct query in passes will enable other valuation
+// mechanisms to produce more precise results.
+
+class value_query
+{
+public:
+  // Return the singleton expression for NAME at a gimple statement,
+  // or NULL if none found.
+  virtual tree value_of_expr (tree name, gimple * = NULL) = 0;
+  // Return the singleton expression for NAME at an edge, or NULL if
+  // none found.
+  virtual tree value_on_edge (edge, tree name);
+  // Return the singleton expression for the LHS of a gimple
+  // statement, assuming an (optional) initial value of NAME.  Returns
+  // NULL if none found.
+  //
+  // Note this method calculates the range the LHS would have *after*
+  // the statement has executed.
+  virtual tree value_of_stmt (gimple *, tree name = NULL);
+};
+
+// range_query is used by optimization passes which are range aware.
+//
+// range_of_expr must be provided.  The default for range_on_edge and
+// range_of_stmt is to call range_of_expr.  If more precise results can
+// be calculated, those functions can be overridden.
+//
+// The default for the value_* routines is to call the equivalent range_*
+// routine, check if the range is a singleton, and return it if so.
+//
+//  get_value_range is currently provided for compatibility with
+//  vr-values.  It will be deprecated when possible.
+
+class range_query : public value_query
+{
+public:
+  range_query ();
+  virtual ~range_query ();
+
+  virtual tree value_of_expr (tree name, gimple * = NULL) OVERRIDE;
+  virtual tree value_on_edge (edge, tree name) OVERRIDE;
+  virtual tree value_of_stmt (gimple *, tree name = NULL) OVERRIDE;
+
+  // These are the range equivalents of the value_* methods.  Instead
+  // of returning a singleton, they calculate a range and return it in
+  // R.  TRUE is returned on success or FALSE if no range was found.
+  virtual bool range_of_expr (irange &r, tree name, gimple * = NULL) = 0;
+  virtual bool range_on_edge (irange &r, edge, tree name);
+  virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL);
+
+  // DEPRECATED: This method is used from vr-values.  The plan is to
+  // rewrite all uses of it to the above API.
+  virtual const class value_range_equiv *get_value_range (const_tree,
+							  gimple * = NULL);
+
+protected:
+  class value_range_equiv *allocate_value_range_equiv ();
+  void free_value_range_equiv (class value_range_equiv *);
+
+private:
+  class equiv_allocator *equiv_alloc;
+};
+
+#endif // GCC_QUERY_H
-- 
2.26.2


[-- Attachment #3: 0002-Convert-vr-values-to-value-query-class.patch --]
[-- Type: text/x-patch, Size: 33437 bytes --]

From 4f75dd0cf5ef817716b133ca71cbbfa78718d9b0 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Thu, 17 Sep 2020 09:34:29 +0200
Subject: [PATCH 2/3] Convert vr-values to value query class.

---
 gcc/gimple-loop-versioning.cc |   8 +--
 gcc/gimple-ssa-evrp-analyze.c |  31 +++++-----
 gcc/gimple-ssa-evrp-analyze.h |  21 +------
 gcc/gimple-ssa-evrp.c         |  20 +++----
 gcc/tree-ssa-ccp.c            |   4 +-
 gcc/tree-ssa-copy.c           |   4 +-
 gcc/tree-ssa-dom.c            |   4 +-
 gcc/tree-ssa-propagate.c      |  13 ++---
 gcc/tree-ssa-propagate.h      |   5 +-
 gcc/tree-ssa-strlen.c         |   2 +-
 gcc/tree-ssa-threadedge.c     |   6 +-
 gcc/tree-vrp.c                |  19 ++----
 gcc/vr-values.c               | 105 ++++++++++++++++++++++++----------
 gcc/vr-values.h               |  43 +++++---------
 14 files changed, 139 insertions(+), 146 deletions(-)

diff --git a/gcc/gimple-loop-versioning.cc b/gcc/gimple-loop-versioning.cc
index 2687088a908..afe353e452d 100644
--- a/gcc/gimple-loop-versioning.cc
+++ b/gcc/gimple-loop-versioning.cc
@@ -277,7 +277,7 @@ private:
   {
   public:
     name_prop (loop_info &li) : m_li (li) {}
-    tree get_value (tree, gimple *) FINAL OVERRIDE;
+    tree value_of_expr (tree name, gimple *) FINAL OVERRIDE;
 
   private:
     /* Information about the versioning we've performed on the loop.  */
@@ -512,8 +512,7 @@ loop_versioning::lv_dom_walker::before_dom_children (basic_block bb)
   m_range_analyzer.enter (bb);
 
   if (bb == bb->loop_father->header)
-    m_lv.prune_loop_conditions (bb->loop_father,
-				m_range_analyzer.get_vr_values ());
+    m_lv.prune_loop_conditions (bb->loop_father, &m_range_analyzer);
 
   for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
        gsi_next (&si))
@@ -534,8 +533,7 @@ loop_versioning::lv_dom_walker::after_dom_children (basic_block bb)
    Return the new value if so, otherwise return null.  */
 
 tree
-loop_versioning::name_prop::get_value (tree val,
-				       gimple *stmt ATTRIBUTE_UNUSED)
+loop_versioning::name_prop::value_of_expr (tree val, gimple *)
 {
   if (TREE_CODE (val) == SSA_NAME
       && bitmap_bit_p (&m_li.unity_names, SSA_NAME_VERSION (val)))
diff --git a/gcc/gimple-ssa-evrp-analyze.c b/gcc/gimple-ssa-evrp-analyze.c
index 9f8ce5575a2..485774d3f22 100644
--- a/gcc/gimple-ssa-evrp-analyze.c
+++ b/gcc/gimple-ssa-evrp-analyze.c
@@ -54,7 +54,6 @@ evrp_range_analyzer::evrp_range_analyzer (bool update_global_ranges)
       FOR_EACH_EDGE (e, ei, bb->preds)
         e->flags |= EDGE_EXECUTABLE;
     }
-  vr_values = new class vr_values;
 }
 
 /* Push an unwinding marker onto the unwinding stack.  */
@@ -87,15 +86,14 @@ evrp_range_analyzer::try_find_new_range (tree name,
   const value_range_equiv *old_vr = get_value_range (name);
 
   /* Discover VR when condition is true.  */
-  vr_values->extract_range_for_var_from_comparison_expr (name, code, op,
-							 limit, &vr);
+  extract_range_for_var_from_comparison_expr (name, code, op, limit, &vr);
   /* If we found any usable VR, set the VR to ssa_name and create a
      PUSH old value in the stack with the old VR.  */
   if (!vr.undefined_p () && !vr.varying_p ())
     {
       if (old_vr->equal_p (vr, /*ignore_equivs=*/true))
 	return NULL;
-      value_range_equiv *new_vr = vr_values->allocate_value_range_equiv ();
+      value_range_equiv *new_vr = allocate_value_range_equiv ();
       new_vr->move (&vr);
       return new_vr;
     }
@@ -214,7 +212,7 @@ evrp_range_analyzer::record_ranges_from_incoming_edge (basic_block bb)
 	      tem.intersect (vrs[i].second);
 	      if (tem.equal_p (*old_vr))
 		{
-		  vr_values->free_value_range (vrs[i].second);
+		  free_value_range (vrs[i].second);
 		  continue;
 		}
 	      push_value_range (vrs[i].first, vrs[i].second);
@@ -261,7 +259,7 @@ evrp_range_analyzer::record_ranges_from_phis (basic_block bb)
       value_range_equiv vr_result;
       bool interesting = stmt_interesting_for_vrp (phi);
       if (!has_unvisited_preds && interesting)
-	vr_values->extract_range_from_phi_node (phi, &vr_result);
+	extract_range_from_phi_node (phi, &vr_result);
       else
 	{
 	  vr_result.set_varying (TREE_TYPE (lhs));
@@ -274,9 +272,9 @@ evrp_range_analyzer::record_ranges_from_phis (basic_block bb)
 	      && interesting
 	      && (l = loop_containing_stmt (phi))
 	      && l->header == gimple_bb (phi))
-	  vr_values->adjust_range_with_scev (&vr_result, l, phi, lhs);
+	  adjust_range_with_scev (&vr_result, l, phi, lhs);
 	}
-      vr_values->update_value_range (lhs, &vr_result);
+      update_value_range (lhs, &vr_result);
 
       /* Set the SSA with the value range.  */
       if (m_update_global_ranges)
@@ -303,7 +301,7 @@ evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary)
     {
       edge taken_edge;
       value_range_equiv vr;
-      vr_values->extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
+      extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
       if (output)
 	{
 	  /* Set the SSA with the value range.  There are two cases to
@@ -321,7 +319,7 @@ evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary)
 	    {
 	      /* Case one.  We can just update the underlying range
 		 information as well as the global information.  */
-	      vr_values->update_value_range (output, &vr);
+	      update_value_range (output, &vr);
 	      if (m_update_global_ranges)
 		set_ssa_range_info (output, &vr);
 	    }
@@ -332,18 +330,17 @@ evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary)
 		 a new range and push the old range onto the stack.  We
 		 also have to be very careful about sharing the underlying
 		 bitmaps.  Ugh.  */
-	      value_range_equiv *new_vr
-		= vr_values->allocate_value_range_equiv ();
+	      value_range_equiv *new_vr = allocate_value_range_equiv ();
 	      new_vr->set (vr.min (), vr.max (), NULL, vr.kind ());
 	      vr.equiv_clear ();
 	      push_value_range (output, new_vr);
 	    }
 	}
       else
-	vr_values->set_defs_to_varying (stmt);
+	set_defs_to_varying (stmt);
     }
   else
-    vr_values->set_defs_to_varying (stmt);
+    set_defs_to_varying (stmt);
 
   /* See if we can derive a range for any of STMT's operands.  */
   tree op;
@@ -429,7 +426,7 @@ evrp_range_analyzer::push_value_range (tree var, value_range_equiv *vr)
       dump_value_range (dump_file, vr);
       fprintf (dump_file, "\n");
     }
-  value_range_equiv *old_vr = vr_values->swap_vr_value (var, vr);
+  value_range_equiv *old_vr = swap_vr_value (var, vr);
   stack.safe_push (std::make_pair (var, old_vr));
 }
 
@@ -451,7 +448,7 @@ evrp_range_analyzer::pop_value_range ()
     }
   /* We saved off a lattice entry, now give it back and release
      the one we popped.  */
-  value_range_equiv *popped_vr = vr_values->swap_vr_value (var, vr);
+  value_range_equiv *popped_vr = swap_vr_value (var, vr);
   if (popped_vr)
-    vr_values->free_value_range (popped_vr);
+    free_value_range (popped_vr);
 }
diff --git a/gcc/gimple-ssa-evrp-analyze.h b/gcc/gimple-ssa-evrp-analyze.h
index 8abbbe3180d..c6d27f5c109 100644
--- a/gcc/gimple-ssa-evrp-analyze.h
+++ b/gcc/gimple-ssa-evrp-analyze.h
@@ -20,13 +20,12 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_GIMPLE_SSA_EVRP_ANALYZE_H
 #define GCC_GIMPLE_SSA_EVRP_ANALYZE_H
 
-class evrp_range_analyzer
+class evrp_range_analyzer : public vr_values
 {
  public:
   evrp_range_analyzer (bool update_global_ranges);
   ~evrp_range_analyzer (void)
   {
-    delete vr_values;
     stack.release ();
   }
 
@@ -36,34 +35,18 @@ class evrp_range_analyzer
   void leave (basic_block);
   void record_ranges_from_stmt (gimple *, bool);
 
-  /* Main interface to retrieve range information.  */
-  const value_range_equiv *get_value_range (const_tree op)
-    { return vr_values->get_value_range (op); }
-
   /* Record a new unwindable range.  */
   void push_value_range (tree var, value_range_equiv *vr);
 
-  /* Dump all the current value ranges.  This is primarily
-     a debugging interface.  */
-  void dump_all_value_ranges (FILE *fp)
-    { vr_values->dump_all_value_ranges (fp); }
-
   /* A bit of a wart.  This should ideally go away.  */
   void vrp_visit_cond_stmt (gcond *cond, edge *e)
   {
-    simplify_using_ranges simpl (vr_values);
+    simplify_using_ranges simpl (this);
     simpl.vrp_visit_cond_stmt (cond, e);
   }
 
-  /* Get the underlying vr_values class instance.  If TRANSFER is
-     true, then we are transferring ownership.  Else we keep ownership.
-
-     This should be converted to a unique_ptr.  */
-  class vr_values *get_vr_values (void) { return vr_values; }
-
  private:
   DISABLE_COPY_AND_ASSIGN (evrp_range_analyzer);
-  class vr_values *vr_values;
 
   void pop_value_range ();
   value_range_equiv *try_find_new_range (tree, tree op, tree_code code,
diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c
index e8fde63aa34..60bf82a6805 100644
--- a/gcc/gimple-ssa-evrp.c
+++ b/gcc/gimple-ssa-evrp.c
@@ -45,11 +45,11 @@ along with GCC; see the file COPYING3.  If not see
 class evrp_folder : public substitute_and_fold_engine
 {
 public:
-  evrp_folder () : m_range_analyzer (/*update_global_ranges=*/true),
-    m_vr_values (m_range_analyzer.get_vr_values ()),
-    simplifier (m_vr_values)
-  {
-  }
+  evrp_folder () :
+    substitute_and_fold_engine (),
+    m_range_analyzer (/*update_global_ranges=*/true),
+    simplifier (&m_range_analyzer)
+  { }
 
   ~evrp_folder ()
   {
@@ -61,9 +61,9 @@ public:
       }
   }
 
-  tree get_value (tree op, gimple *stmt ATTRIBUTE_UNUSED) OVERRIDE
+  tree value_of_expr (tree name, gimple *stmt) OVERRIDE
   {
-    return m_vr_values->op_with_constant_singleton_value_range (op);
+    return m_range_analyzer.value_of_expr (name, stmt);
   }
 
   void pre_fold_bb (basic_block bb) OVERRIDE
@@ -95,14 +95,12 @@ public:
 
   void post_new_stmt (gimple *stmt) OVERRIDE
   {
-    m_range_analyzer.get_vr_values ()->set_defs_to_varying (stmt);
+    m_range_analyzer.set_defs_to_varying (stmt);
   }
 
 private:
   DISABLE_COPY_AND_ASSIGN (evrp_folder);
-  class evrp_range_analyzer m_range_analyzer;
-  class vr_values *m_vr_values;
-
+  evrp_range_analyzer m_range_analyzer;
   simplify_using_ranges simplifier;
 };
 
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index 65dffe06530..0432fe5513d 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -946,7 +946,7 @@ do_dbg_cnt (void)
 class ccp_folder : public substitute_and_fold_engine
 {
  public:
-  tree get_value (tree, gimple *) FINAL OVERRIDE;
+  tree value_of_expr (tree, gimple *) FINAL OVERRIDE;
   bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE;
 };
 
@@ -955,7 +955,7 @@ class ccp_folder : public substitute_and_fold_engine
    of calling member functions.  */
 
 tree
-ccp_folder::get_value (tree op, gimple *stmt ATTRIBUTE_UNUSED)
+ccp_folder::value_of_expr (tree op, gimple *)
 {
   return get_constant_value (op);
 }
diff --git a/gcc/tree-ssa-copy.c b/gcc/tree-ssa-copy.c
index 9bcb708379e..3d779825829 100644
--- a/gcc/tree-ssa-copy.c
+++ b/gcc/tree-ssa-copy.c
@@ -492,13 +492,13 @@ init_copy_prop (void)
 class copy_folder : public substitute_and_fold_engine
 {
  public:
-  tree get_value (tree, gimple *) FINAL OVERRIDE;
+  tree value_of_expr (tree name, gimple *) FINAL OVERRIDE;
 };
 
 /* Callback for substitute_and_fold to get at the final copy-of values.  */
 
 tree
-copy_folder::get_value (tree name, gimple *stmt ATTRIBUTE_UNUSED)
+copy_folder::value_of_expr (tree name, gimple *)
 {
   tree val;
   if (SSA_NAME_VERSION (name) >= n_copy_of)
diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
index de5025f3879..c21bfe9f64e 100644
--- a/gcc/tree-ssa-dom.c
+++ b/gcc/tree-ssa-dom.c
@@ -1500,7 +1500,7 @@ dom_opt_dom_walker::before_dom_children (basic_block bb)
 void
 dom_opt_dom_walker::after_dom_children (basic_block bb)
 {
-  x_vr_values = evrp_range_analyzer.get_vr_values ();
+  x_vr_values = &evrp_range_analyzer;
   thread_outgoing_edges (bb, m_dummy_cond, m_const_and_copies,
 			 m_avail_exprs_stack,
 			 &evrp_range_analyzer,
@@ -1970,7 +1970,7 @@ dom_opt_dom_walker::optimize_stmt (basic_block bb, gimple_stmt_iterator *si,
   opt_stats.num_stmts++;
 
   /* Const/copy propagate into USES, VUSES and the RHS of VDEFs.  */
-  cprop_into_stmt (stmt, evrp_range_analyzer.get_vr_values ());
+  cprop_into_stmt (stmt, &evrp_range_analyzer);
 
   /* If the statement has been modified with constant replacements,
      fold its RHS before checking for redundant computations.  */
diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c
index 5a30176d3b4..87dbf55fab9 100644
--- a/gcc/tree-ssa-propagate.c
+++ b/gcc/tree-ssa-propagate.c
@@ -868,7 +868,7 @@ substitute_and_fold_engine::replace_uses_in (gimple *stmt)
   FOR_EACH_SSA_USE_OPERAND (use, stmt, iter, SSA_OP_USE)
     {
       tree tuse = USE_FROM_PTR (use);
-      tree val = get_value (tuse, stmt);
+      tree val = value_of_expr (tuse, stmt);
 
       if (val == tuse || val == NULL_TREE)
 	continue;
@@ -909,12 +909,11 @@ substitute_and_fold_engine::replace_phi_args_in (gphi *phi)
 
       if (TREE_CODE (arg) == SSA_NAME)
 	{
-	  tree val = get_value (arg, phi);
+	  edge e = gimple_phi_arg_edge (phi, i);
+	  tree val = value_on_edge (e, arg);
 
 	  if (val && val != arg && may_propagate_copy (arg, val))
 	    {
-	      edge e = gimple_phi_arg_edge (phi, i);
-
 	      if (TREE_CODE (val) != SSA_NAME)
 		prop_stats.num_const_prop++;
 	      else
@@ -1036,7 +1035,7 @@ substitute_and_fold_engine::propagate_into_phi_args (basic_block bb)
 	  if (TREE_CODE (arg) != SSA_NAME
 	      || virtual_operand_p (arg))
 	    continue;
-	  tree val = get_value (arg, phi);
+	  tree val = value_on_edge (e, arg);
 	  if (val
 	      && is_gimple_min_invariant (val)
 	      && may_propagate_copy (arg, val))
@@ -1070,7 +1069,7 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
 	}
       if (res && TREE_CODE (res) == SSA_NAME)
 	{
-	  tree sprime = substitute_and_fold_engine->get_value (res, phi);
+	  tree sprime = substitute_and_fold_engine->value_of_expr (res, phi);
 	  if (sprime
 	      && sprime != res
 	      && may_propagate_copy (res, sprime))
@@ -1110,7 +1109,7 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
       tree lhs = gimple_get_lhs (stmt);
       if (lhs && TREE_CODE (lhs) == SSA_NAME)
 	{
-	  tree sprime = substitute_and_fold_engine->get_value (lhs, stmt);
+	  tree sprime = substitute_and_fold_engine->value_of_expr (lhs, stmt);
 	  if (sprime
 	      && sprime != lhs
 	      && may_propagate_copy (lhs, sprime)
diff --git a/gcc/tree-ssa-propagate.h b/gcc/tree-ssa-propagate.h
index 9406cdf8f51..da362ab562d 100644
--- a/gcc/tree-ssa-propagate.h
+++ b/gcc/tree-ssa-propagate.h
@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef _TREE_SSA_PROPAGATE_H
 #define _TREE_SSA_PROPAGATE_H 1
 
+#include "value-query.h"
+
 /* If SIM_P is true, statement S will be simulated again.  */
 
 static inline void
@@ -97,14 +99,13 @@ class ssa_propagation_engine
   void simulate_block (basic_block);
 };
 
-class substitute_and_fold_engine
+class substitute_and_fold_engine : public value_query
 {
  public:
   substitute_and_fold_engine (bool fold_all_stmts = false)
     : fold_all_stmts (fold_all_stmts) { }
   virtual ~substitute_and_fold_engine (void) { }
   virtual bool fold_stmt (gimple_stmt_iterator *) { return false; }
-  virtual tree get_value (tree, gimple *) { return NULL_TREE; }
 
   bool substitute_and_fold (basic_block = NULL);
   bool replace_uses_in (gimple *);
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 47f537ab210..9907cc0c824 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -5860,7 +5860,7 @@ strlen_dom_walker::before_dom_children (basic_block bb)
 	 can be used by printf argument processing.  */
       evrp.record_ranges_from_stmt (stmt, false);
 
-      if (check_and_optimize_stmt (&gsi, &cleanup_eh, evrp.get_vr_values ()))
+      if (check_and_optimize_stmt (&gsi, &cleanup_eh, &evrp))
 	gsi_next (&gsi);
     }
 
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index 03a210846cb..f43d5812270 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -163,8 +163,8 @@ record_temporary_equivalences_from_phis (edge e,
 	{
 	  /* Get an empty new VR we can pass to update_value_range and save
 	     away in the VR stack.  */
-	  vr_values *vr_values = evrp_range_analyzer->get_vr_values ();
-	  value_range_equiv *new_vr = vr_values->allocate_value_range_equiv ();
+	  value_range_equiv *new_vr
+			  = evrp_range_analyzer->allocate_value_range_equiv ();
 	  new (new_vr) value_range_equiv ();
 
 	  /* There are three cases to consider:
@@ -178,7 +178,7 @@ record_temporary_equivalences_from_phis (edge e,
 	       Otherwise set NEW_VR to varying.  This may be overly
 	       conservative.  */
 	  if (TREE_CODE (src) == SSA_NAME)
-	    new_vr->deep_copy (vr_values->get_value_range (src));
+	    new_vr->deep_copy (evrp_range_analyzer->get_value_range (src));
 	  else if (TREE_CODE (src) == INTEGER_CST)
 	    new_vr->set (src);
 	  else
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index b493e402382..0e19690f41f 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -4010,9 +4010,12 @@ class vrp_folder : public substitute_and_fold_engine
     : substitute_and_fold_engine (/* Fold all stmts.  */ true),
       m_vr_values (v), simplifier (v)
     {  }
-  tree get_value (tree, gimple *stmt) FINAL OVERRIDE;
   bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE;
 
+  tree value_of_expr (tree name, gimple *stmt) OVERRIDE
+    {
+      return m_vr_values->value_of_expr (name, stmt);
+    }
   class vr_values *m_vr_values;
 
 private:
@@ -4023,8 +4026,6 @@ private:
     { return simplifier.vrp_evaluate_conditional (code, op0, op1, stmt); }
   bool simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
     { return simplifier.simplify (gsi); }
- tree op_with_constant_singleton_value_range (tree op)
-    { return m_vr_values->op_with_constant_singleton_value_range (op); }
 
   simplify_using_ranges simplifier;
 };
@@ -4102,18 +4103,6 @@ vrp_folder::fold_stmt (gimple_stmt_iterator *si)
   return simplify_stmt_using_ranges (si);
 }
 
-/* If OP has a value range with a single constant value return that,
-   otherwise return NULL_TREE.  This returns OP itself if OP is a
-   constant.
-
-   Implemented as a pure wrapper right now, but this will change.  */
-
-tree
-vrp_folder::get_value (tree op, gimple *stmt ATTRIBUTE_UNUSED)
-{
-  return op_with_constant_singleton_value_range (op);
-}
-
 /* Return the LHS of any ASSERT_EXPR where OP appears as the first
    argument to the ASSERT_EXPR and in which the ASSERT_EXPR dominates
    BB.  If no such ASSERT_EXPR is found, return OP.  */
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index 9b21441dff3..4d7dfd0b4bf 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -92,7 +92,7 @@ vr_values::get_lattice_entry (const_tree var)
     return vr;
 
   /* Create a default value range.  */
-  vr = new (vrp_value_range_pool.allocate ()) value_range_equiv;
+  vr = allocate_value_range_equiv ();
   vr_value[ver] = vr;
 
   /* After propagation finished return varying.  */
@@ -173,6 +173,49 @@ vr_values::get_value_range (const_tree var,
   return vr;
 }
 
+bool
+vr_values::range_of_expr (irange &r, tree name, gimple *stmt)
+{
+  if (const value_range *vr = get_value_range (name, stmt))
+    {
+      if (vr->undefined_p () || vr->varying_p () || vr->constant_p ())
+	r = *vr;
+      else
+	{
+	  value_range tmp = *vr;
+	  tmp.normalize_symbolics ();
+	  r = tmp;
+	}
+      return true;
+    }
+  return false;
+}
+
+tree
+vr_values::value_of_expr (tree op, gimple *)
+{
+  return op_with_constant_singleton_value_range (op);
+}
+
+tree
+vr_values::value_on_edge (edge, tree op)
+{
+  return op_with_constant_singleton_value_range (op);
+}
+
+tree
+vr_values::value_of_stmt (gimple *stmt, tree op)
+{
+  if (!op)
+    op = gimple_get_lhs (stmt);
+
+  gcc_checking_assert (!op|| op == gimple_get_lhs (stmt));
+
+  if (op)
+    return op_with_constant_singleton_value_range (op);
+  return NULL_TREE;
+}
+
 /* Set the lattice entry for DEF to VARYING.  */
 
 void
@@ -451,7 +494,7 @@ simplify_using_ranges::op_with_boolean_value_range_p (tree op)
 
   /* ?? Errr, this should probably check for [0,0] and [1,1] as well
      as [0,1].  */
-  const value_range *vr = get_value_range (op);
+  const value_range *vr = query->get_value_range (op);
   return *vr == value_range (build_zero_cst (TREE_TYPE (op)),
 			     build_one_cst (TREE_TYPE (op)));
 }
@@ -1006,20 +1049,20 @@ vr_values::extract_range_from_comparison (value_range_equiv *vr,
    overflow.  */
 
 static bool
-check_for_binary_op_overflow (range_query *store,
+check_for_binary_op_overflow (range_query *query,
 			      enum tree_code subcode, tree type,
 			      tree op0, tree op1, bool *ovf)
 {
   value_range vr0, vr1;
   if (TREE_CODE (op0) == SSA_NAME)
-    vr0 = *store->get_value_range (op0);
+    vr0 = *query->get_value_range (op0);
   else if (TREE_CODE (op0) == INTEGER_CST)
     vr0.set (op0);
   else
     vr0.set_varying (TREE_TYPE (op0));
 
   if (TREE_CODE (op1) == SSA_NAME)
-    vr1 = *store->get_value_range (op1);
+    vr1 = *query->get_value_range (op1);
   else if (TREE_CODE (op1) == INTEGER_CST)
     vr1.set (op1);
   else
@@ -1948,8 +1991,7 @@ vr_values::dump_all_value_ranges (FILE *file)
 
 /* Initialize VRP lattice.  */
 
-vr_values::vr_values () : vrp_value_range_pool ("Tree VRP value ranges"),
-  simplifier (this)
+vr_values::vr_values () : simplifier (this)
 {
   values_propagated = false;
   num_vr_values = num_ssa_names * 2;
@@ -1966,7 +2008,6 @@ vr_values::~vr_values ()
   free (vr_value);
   free (vr_phi_edge_counts);
   bitmap_obstack_release (&vrp_equiv_obstack);
-  vrp_value_range_pool.release ();
 
   /* So that we can distinguish between VRP data being available
      and not available.  */
@@ -2092,7 +2133,7 @@ const value_range_equiv *
 simplify_using_ranges::get_vr_for_comparison (int i, value_range_equiv *tem)
 {
   /* Shallow-copy equiv bitmap.  */
-  const value_range_equiv *vr = get_value_range (ssa_name (i));
+  const value_range_equiv *vr = query->get_value_range (ssa_name (i));
 
   /* If name N_i does not have a valid range, use N_i as its own
      range.  This allows us to compare against names that may
@@ -2117,7 +2158,7 @@ simplify_using_ranges::compare_name_with_value
 				 bool *strict_overflow_p, bool use_equiv_p)
 {
   /* Get the set of equivalences for VAR.  */
-  bitmap e = get_value_range (var)->equiv ();
+  bitmap e = query->get_value_range (var)->equiv ();
 
   /* Start at -1.  Set it to 0 if we do a comparison without relying
      on overflow, or 1 if all comparisons rely on overflow.  */
@@ -2197,8 +2238,8 @@ simplify_using_ranges::compare_names (enum tree_code comp, tree n1, tree n2,
 {
   /* Compare the ranges of every name equivalent to N1 against the
      ranges of every name equivalent to N2.  */
-  bitmap e1 = get_value_range (n1)->equiv ();
-  bitmap e2 = get_value_range (n2)->equiv ();
+  bitmap e1 = query->get_value_range (n1)->equiv ();
+  bitmap e2 = query->get_value_range (n2)->equiv ();
 
   /* Use the fake bitmaps if e1 or e2 are not available.  */
   static bitmap s_e1 = NULL, s_e2 = NULL;
@@ -2310,8 +2351,8 @@ simplify_using_ranges::vrp_evaluate_conditional_warnv_with_ops_using_ranges
     (enum tree_code code, tree op0, tree op1, bool * strict_overflow_p)
 {
   const value_range_equiv *vr0, *vr1;
-  vr0 = (TREE_CODE (op0) == SSA_NAME) ? get_value_range (op0) : NULL;
-  vr1 = (TREE_CODE (op1) == SSA_NAME) ? get_value_range (op1) : NULL;
+  vr0 = (TREE_CODE (op0) == SSA_NAME) ? query->get_value_range (op0) : NULL;
+  vr1 = (TREE_CODE (op1) == SSA_NAME) ? query->get_value_range (op1) : NULL;
 
   tree res = NULL_TREE;
   if (vr0 && vr1)
@@ -2390,7 +2431,7 @@ simplify_using_ranges::vrp_evaluate_conditional_warnv_with_ops
 	    }
 	  else
 	    gcc_unreachable ();
-	  const value_range_equiv *vr0 = get_value_range (op0, stmt);
+	  const value_range_equiv *vr0 = query->get_value_range (op0, stmt);
 	  /* If vro, the range for OP0 to pass the overflow test, has
 	     no intersection with *vr0, OP0's known range, then the
 	     overflow test can't pass, so return the node for false.
@@ -2496,7 +2537,7 @@ simplify_using_ranges::vrp_evaluate_conditional (tree_code code, tree op0,
 	 always fold regardless of the value of OP0.  If -Wtype-limits
 	 was specified, emit a warning.  */
       tree type = TREE_TYPE (op0);
-      const value_range_equiv *vr0 = get_value_range (op0, stmt);
+      const value_range_equiv *vr0 = query->get_value_range (op0, stmt);
 
       if (vr0->varying_p ()
 	  && INTEGRAL_TYPE_P (type)
@@ -2547,7 +2588,7 @@ simplify_using_ranges::vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p)
 	  fprintf (dump_file, "\t");
 	  print_generic_expr (dump_file, use);
 	  fprintf (dump_file, ": ");
-	  dump_value_range (dump_file, get_value_range (use, stmt));
+	  dump_value_range (dump_file, query->get_value_range (use, stmt));
 	}
 
       fprintf (dump_file, "\n");
@@ -3123,7 +3164,7 @@ simplify_using_ranges::simplify_div_or_mod_using_ranges
     }
   else
     {
-      vr = get_value_range (op0, stmt);
+      vr = query->get_value_range (op0, stmt);
       if (range_int_cst_p (vr))
 	{
 	  op0min = vr->min ();
@@ -3134,7 +3175,7 @@ simplify_using_ranges::simplify_div_or_mod_using_ranges
   if (rhs_code == TRUNC_MOD_EXPR
       && TREE_CODE (op1) == SSA_NAME)
     {
-      const value_range_equiv *vr1 = get_value_range (op1, stmt);
+      const value_range_equiv *vr1 = query->get_value_range (op1, stmt);
       if (range_int_cst_p (vr1))
 	op1min = vr1->min ();
     }
@@ -3283,7 +3324,7 @@ simplify_using_ranges::simplify_abs_using_ranges (gimple_stmt_iterator *gsi,
 						  gimple *stmt)
 {
   tree op = gimple_assign_rhs1 (stmt);
-  const value_range *vr = get_value_range (op, stmt);
+  const value_range *vr = query->get_value_range (op, stmt);
 
   if (vr)
     {
@@ -3373,14 +3414,14 @@ simplify_using_ranges::simplify_bit_ops_using_ranges
   wide_int mask;
 
   if (TREE_CODE (op0) == SSA_NAME)
-    vr0 = *(get_value_range (op0, stmt));
+    vr0 = *(query->get_value_range (op0, stmt));
   else if (is_gimple_min_invariant (op0))
     vr0.set (op0);
   else
     return false;
 
   if (TREE_CODE (op1) == SSA_NAME)
-    vr1 = *(get_value_range (op1, stmt));
+    vr1 = *(query->get_value_range (op1, stmt));
   else if (is_gimple_min_invariant (op1))
     vr1.set (op1);
   else
@@ -3599,7 +3640,7 @@ simplify_using_ranges::simplify_cond_using_ranges_1 (gcond *stmt)
       && INTEGRAL_TYPE_P (TREE_TYPE (op0))
       && is_gimple_min_invariant (op1))
     {
-      const value_range *vr = get_value_range (op0, stmt);
+      const value_range *vr = query->get_value_range (op0, stmt);
 
       /* If we have range information for OP0, then we might be
 	 able to simplify this conditional. */
@@ -3672,7 +3713,7 @@ simplify_using_ranges::simplify_cond_using_ranges_1 (gcond *stmt)
    subsequent passes.  */
 
 void
-simplify_cond_using_ranges_2 (vr_values *store, gcond *stmt)
+simplify_cond_using_ranges_2 (vr_values *query, gcond *stmt)
 {
   tree op0 = gimple_cond_lhs (stmt);
   tree op1 = gimple_cond_rhs (stmt);
@@ -3702,7 +3743,7 @@ simplify_cond_using_ranges_2 (vr_values *store, gcond *stmt)
 	  && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop)
 	  && desired_pro_or_demotion_p (TREE_TYPE (innerop), TREE_TYPE (op0)))
 	{
-	  const value_range *vr = store->get_value_range (innerop);
+	  const value_range *vr = query->get_value_range (innerop);
 
 	  if (range_int_cst_p (vr)
 	      && range_fits_type_p (vr,
@@ -3743,7 +3784,7 @@ simplify_using_ranges::simplify_switch_using_ranges (gswitch *stmt)
 
   if (TREE_CODE (op) == SSA_NAME)
     {
-      vr = get_value_range (op, stmt);
+      vr = query->get_value_range (op, stmt);
 
       /* We can only handle integer ranges.  */
       if (vr->varying_p ()
@@ -4036,7 +4077,7 @@ simplify_using_ranges::simplify_float_conversion_using_ranges
 					 gimple *stmt)
 {
   tree rhs1 = gimple_assign_rhs1 (stmt);
-  const value_range *vr = get_value_range (rhs1, stmt);
+  const value_range *vr = query->get_value_range (rhs1, stmt);
   scalar_float_mode fltmode
     = SCALAR_FLOAT_TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt)));
   scalar_int_mode mode;
@@ -4141,7 +4182,7 @@ simplify_using_ranges::simplify_internal_call_using_ranges
     return false;
   else
     type = TREE_TYPE (TREE_TYPE (gimple_call_lhs (stmt)));
-  if (!check_for_binary_op_overflow (store, subcode, type, op0, op1, &ovf)
+  if (!check_for_binary_op_overflow (query, subcode, type, op0, op1, &ovf)
       || (is_ubsan && ovf))
     return false;
 
@@ -4200,7 +4241,7 @@ simplify_using_ranges::simplify_internal_call_using_ranges
 bool
 simplify_using_ranges::two_valued_val_range_p (tree var, tree *a, tree *b)
 {
-  value_range vr = *get_value_range (var);
+  value_range vr = *query->get_value_range (var);
   vr.normalize_symbolics ();
   if (vr.varying_p () || vr.undefined_p ())
     return false;
@@ -4217,8 +4258,8 @@ simplify_using_ranges::two_valued_val_range_p (tree var, tree *a, tree *b)
   return false;
 }
 
-simplify_using_ranges::simplify_using_ranges (range_query *store)
-  : store (store)
+simplify_using_ranges::simplify_using_ranges (range_query *query)
+  : query (query)
 {
   to_remove_edges = vNULL;
   to_update_switch_stmts = vNULL;
@@ -4234,6 +4275,8 @@ simplify_using_ranges::~simplify_using_ranges ()
 bool
 simplify_using_ranges::simplify (gimple_stmt_iterator *gsi)
 {
+  gcc_checking_assert (query);
+
   gimple *stmt = gsi_stmt (*gsi);
   if (is_gimple_assign (stmt))
     {
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index 7051e13fc00..a30f05cbeaa 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -21,28 +21,19 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_VR_VALUES_H
 
 #include "value-range-equiv.h"
+#include "value-query.h"
 
 // Abstract class to return a range for a given SSA.
 
-class range_query
-{
-public:
-  virtual const value_range_equiv *get_value_range (const_tree,
-						    gimple * = NULL) = 0;
-  virtual ~range_query () { }
-};
-
 // Class to simplify a statement using range information.
-//
-// The constructor takes a full vr_values, but all it needs is
-// get_value_range() from it.  This class could be made to work with
-// any range repository.
 
-class simplify_using_ranges : public range_query
+class simplify_using_ranges
 {
 public:
-  simplify_using_ranges (class range_query *);
+  simplify_using_ranges (class range_query *query = NULL);
   ~simplify_using_ranges ();
+  void set_range_query (class range_query *q) { query = q; }
+
   bool simplify (gimple_stmt_iterator *);
 
   // ?? These should be cleaned, merged, and made private.
@@ -53,8 +44,6 @@ public:
 						bool *, bool *);
 
 private:
-  const value_range_equiv *get_value_range (const_tree op,
-					    gimple *stmt = NULL) OVERRIDE;
   bool simplify_truth_ops_using_ranges (gimple_stmt_iterator *, gimple *);
   bool simplify_div_or_mod_using_ranges (gimple_stmt_iterator *, gimple *);
   bool simplify_abs_using_ranges (gimple_stmt_iterator *, gimple *);
@@ -89,7 +78,7 @@ private:
 
   vec<edge> to_remove_edges;
   vec<switch_update> to_update_switch_stmts;
-  class range_query *store;
+  class range_query *query;
 };
 
 /* The VR_VALUES class holds the current view of range information
@@ -112,7 +101,12 @@ class vr_values : public range_query
   vr_values (void);
   ~vr_values (void);
 
-  const value_range_equiv *get_value_range (const_tree, gimple * = NULL);
+  virtual bool range_of_expr (irange &r, tree name, gimple *stmt) OVERRIDE;
+  virtual tree value_of_expr (tree, gimple * = NULL) OVERRIDE;
+  virtual tree value_on_edge (edge, tree) OVERRIDE;
+  virtual tree value_of_stmt (gimple *, tree = NULL_TREE) OVERRIDE;
+  virtual const value_range_equiv *get_value_range (const_tree,
+						    gimple * = NULL) OVERRIDE;
   void set_vr_value (tree, value_range_equiv *);
   value_range_equiv *swap_vr_value (tree, value_range_equiv *);
 
@@ -136,9 +130,9 @@ class vr_values : public range_query
 
   /* Allocate a new value_range object.  */
   value_range_equiv *allocate_value_range_equiv (void)
-    { return vrp_value_range_pool.allocate (); }
+    { return range_query::allocate_value_range_equiv (); }
   void free_value_range (value_range_equiv *vr)
-    { vrp_value_range_pool.remove (vr); }
+    { free_value_range_equiv (vr); }
 
  private:
   value_range_equiv *get_lattice_entry (const_tree);
@@ -155,9 +149,6 @@ class vr_values : public range_query
   void vrp_visit_assignment_or_call (gimple*, tree *, value_range_equiv *);
   void vrp_visit_switch_stmt (gswitch *, edge *);
 
-  /* Allocation pools for value_range objects.  */
-  object_allocator<value_range_equiv> vrp_value_range_pool;
-
   /* This probably belongs in the lattice rather than in here.  */
   bool values_propagated;
 
@@ -176,12 +167,6 @@ class vr_values : public range_query
   simplify_using_ranges simplifier;
 };
 
-inline const value_range_equiv *
-simplify_using_ranges::get_value_range (const_tree op, gimple *stmt)
-{
-  return store->get_value_range (op, stmt);
-}
-
 extern tree get_output_for_vrp (gimple *);
 
 // FIXME: Move this to tree-vrp.c.
-- 
2.26.2


[-- Attachment #4: 0003-Convert-sprintf-strlen-passes-to-value-query-class.patch --]
[-- Type: text/x-patch, Size: 43498 bytes --]

From 75e48c3b6d0d744e511edfa075a50f635c879aa8 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Thu, 17 Sep 2020 09:34:03 +0200
Subject: [PATCH 3/3] Convert sprintf/strlen passes to value query class.

---
 gcc/builtins.c           |  29 +++---
 gcc/builtins.h           |   5 +-
 gcc/gimple-ssa-sprintf.c | 136 +++++++++++++++------------
 gcc/tree-ssa-strlen.c    | 193 ++++++++++++++++++++-------------------
 gcc/tree-ssa-strlen.h    |   9 +-
 5 files changed, 196 insertions(+), 176 deletions(-)

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 97f1a184dc6..fb94c8e0ac0 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -183,8 +183,9 @@ static void maybe_emit_chk_warning (tree, enum built_in_function);
 static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
 static void maybe_emit_free_warning (tree);
 static tree fold_builtin_object_size (tree, tree);
-static tree compute_objsize (tree, int, access_ref *, const vr_values * = NULL);
-static bool get_range (tree, signop, offset_int[2], const vr_values * = NULL);
+static tree compute_objsize (tree, int, access_ref *, range_query * = NULL);
+static bool get_range (tree, gimple *, signop, offset_int[2],
+		       range_query * = NULL);
 static bool check_read_access (tree, tree, tree = NULL_TREE, int = 1);
 
 unsigned HOST_WIDE_INT target_newline;
@@ -4070,7 +4071,7 @@ check_read_access (tree exp, tree src, tree bound /* = NULL_TREE */,
 
 tree
 gimple_call_alloc_size (gimple *stmt, wide_int rng1[2] /* = NULL */,
-			const vr_values *rvals /* = NULL */)
+			range_query *rvals /* = NULL */)
 {
   if (!stmt)
     return NULL_TREE;
@@ -4122,7 +4123,7 @@ gimple_call_alloc_size (gimple *stmt, wide_int rng1[2] /* = NULL */,
   if (!rng1)
     rng1 = rng1_buf;
 
-  if (!get_range (size, rng1, rvals))
+  if (!get_range (size, stmt, rng1, rvals))
     return NULL_TREE;
 
   if (argidx2 > nargs && TREE_CODE (size) == INTEGER_CST)
@@ -4132,7 +4133,7 @@ gimple_call_alloc_size (gimple *stmt, wide_int rng1[2] /* = NULL */,
      of the upper bounds as a constant.  Ignore anti-ranges.  */
   tree n = argidx2 < nargs ? gimple_call_arg (stmt, argidx2) : integer_one_node;
   wide_int rng2[2];
-  if (!get_range (n, rng2, rvals))
+  if (!get_range (n, stmt, rng2, rvals))
     return NULL_TREE;
 
   /* Extend to the maximum precision to avoid overflow.  */
@@ -4160,11 +4161,11 @@ gimple_call_alloc_size (gimple *stmt, wide_int rng1[2] /* = NULL */,
    result but accepts offset_int instead.  */
 
 static bool
-get_range (tree x, signop sgn, offset_int r[2],
-	   const vr_values *rvals /* = NULL */)
+get_range (tree x, gimple *stmt, signop sgn, offset_int r[2],
+	   range_query *rvals /* = NULL */)
 {
   wide_int wr[2];
-  if (!get_range (x, wr, rvals))
+  if (!get_range (x, stmt, wr, rvals))
     return false;
 
   r[0] = offset_int::from (wr[0], sgn);
@@ -4188,7 +4189,7 @@ get_range (tree x, signop sgn, offset_int r[2],
 
 static bool
 compute_objsize (tree ptr, int ostype, access_ref *pref,
-		 bitmap *visited, const vr_values *rvals /* = NULL */)
+		 bitmap *visited, range_query *rvals /* = NULL */)
 {
   const bool addr = TREE_CODE (ptr) == ADDR_EXPR;
   if (addr)
@@ -4286,7 +4287,7 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
 
       offset_int orng[2];
       tree off = TREE_OPERAND (ptr, 1);
-      if (!get_range (off, SIGNED, orng, rvals))
+      if (!get_range (off, NULL, SIGNED, orng, rvals))
 	/* Fail unless the size of the object is zero.  */
 	return pref->sizrng[0] == 0 && pref->sizrng[0] == pref->sizrng[1];
 
@@ -4367,7 +4368,7 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
 	     offset to the maximum.  */
 	  offset_int orng[2];
 	  tree off = gimple_assign_rhs2 (stmt);
-	  if (!get_range (off, SIGNED, orng, rvals))
+	  if (!get_range (off, stmt, SIGNED, orng, rvals))
 	    {
 	      orng[0] = wi::to_offset (TYPE_MIN_VALUE (ptrdiff_type_node));
 	      orng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
@@ -4397,7 +4398,7 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
       && !array_at_struct_end_p (ptr))
     {
       if (tree size = TYPE_SIZE_UNIT (type))
-	return get_range (size, UNSIGNED, pref->sizrng, rvals);
+	return get_range (size, NULL, UNSIGNED, pref->sizrng, rvals);
     }
 
   return false;
@@ -4407,7 +4408,7 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
 
 static tree
 compute_objsize (tree ptr, int ostype, access_ref *pref,
-		 const vr_values *rvals /* = NULL */)
+		 range_query *rvals /* = NULL */)
 {
   bitmap visited = NULL;
 
@@ -4439,7 +4440,7 @@ compute_objsize (tree ptr, int ostype, access_ref *pref,
 
 tree
 compute_objsize (tree ptr, int ostype, tree *pdecl /* = NULL */,
-		 tree *poff /* = NULL */, const vr_values *rvals /* = NULL */)
+		 tree *poff /* = NULL */, class range_query *rvals /* = NULL */)
 {
   /* Set the initial offsets to zero and size to negative to indicate
      none has been computed yet.  */
diff --git a/gcc/builtins.h b/gcc/builtins.h
index 94ff96b1292..5ebde7930cb 100644
--- a/gcc/builtins.h
+++ b/gcc/builtins.h
@@ -134,11 +134,10 @@ extern void set_builtin_user_assembler_name (tree decl, const char *asmspec);
 extern bool is_simple_builtin (tree);
 extern bool is_inexpensive_builtin (tree);
 
-class vr_values;
 tree gimple_call_alloc_size (gimple *, wide_int[2] = NULL,
-			     const vr_values * = NULL);
+			     class range_query * = NULL);
 extern tree compute_objsize (tree, int, tree * = NULL, tree * = NULL,
-			     const vr_values * = NULL);
+			     class range_query * = NULL);
 
 extern bool readonly_data_expr (tree exp);
 extern bool init_target_chars (void);
diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
index 70b031fe7b9..8b173987532 100644
--- a/gcc/gimple-ssa-sprintf.c
+++ b/gcc/gimple-ssa-sprintf.c
@@ -546,8 +546,8 @@ fmtresult::type_max_digits (tree type, int base)
 }
 
 static bool
-get_int_range (tree, HOST_WIDE_INT *, HOST_WIDE_INT *, bool, HOST_WIDE_INT,
-	       const vr_values *);
+get_int_range (tree, gimple *, HOST_WIDE_INT *, HOST_WIDE_INT *,
+	       bool, HOST_WIDE_INT, range_query *);
 
 struct call_info;
 
@@ -597,7 +597,7 @@ struct directive
 
   /* Format conversion function that given a directive and an argument
      returns the formatting result.  */
-  fmtresult (*fmtfunc) (const directive &, tree, const vr_values *);
+  fmtresult (*fmtfunc) (gimple *, const directive &, tree, range_query *);
 
   /* Return True when the format flag CHR has been used.  */
   bool get_flag (char chr) const
@@ -634,10 +634,7 @@ struct directive
      or 0, whichever is greater.  For a non-constant ARG in some range
      set width to its range adjusting each bound to -1 if it's less.
      For an indeterminate ARG set width to [0, INT_MAX].  */
-  void set_width (tree arg, const vr_values *vr)
-  {
-    get_int_range (arg, width, width + 1, true, 0, vr);
-  }
+  void set_width (tree arg, range_query *);
 
   /* Set both bounds of the precision range to VAL.  */
   void set_precision (HOST_WIDE_INT val)
@@ -650,10 +647,7 @@ struct directive
      or -1 whichever is greater.  For a non-constant ARG in some range
      set precision to its range adjusting each bound to -1 if it's less.
      For an indeterminate ARG set precision to [-1, INT_MAX].  */
-  void set_precision (tree arg, const vr_values *vr)
-  {
-    get_int_range (arg, prec, prec + 1, false, -1, vr);
-  }
+  void set_precision (tree arg, range_query *query);
 
   /* Return true if both width and precision are known to be
      either constant or in some range, false otherwise.  */
@@ -956,10 +950,22 @@ struct call_info
   }
 };
 
+void
+directive::set_width (tree arg, range_query *query)
+{
+  get_int_range (arg, info->callstmt, width, width + 1, true, 0, query);
+}
+
+void
+directive::set_precision (tree arg, range_query *query)
+{
+  get_int_range (arg, info->callstmt, prec, prec + 1, false, -1, query);
+}
+
 /* Return the result of formatting a no-op directive (such as '%n').  */
 
 static fmtresult
-format_none (const directive &, tree, const vr_values *)
+format_none (gimple *, const directive &, tree, range_query *)
 {
   fmtresult res (0);
   return res;
@@ -968,7 +974,7 @@ format_none (const directive &, tree, const vr_values *)
 /* Return the result of formatting the '%%' directive.  */
 
 static fmtresult
-format_percent (const directive &, tree, const vr_values *)
+format_percent (gimple *, const directive &, tree, range_query *)
 {
   fmtresult res (1);
   return res;
@@ -1026,9 +1032,10 @@ build_intmax_type_nodes (tree *pintmax, tree *puintmax)
    the determined range are replaced with NEGBOUND.  */
 
 static bool
-get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
+get_int_range (tree arg, gimple *stmt,
+	       HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
 	       bool absolute, HOST_WIDE_INT negbound,
-	       const class vr_values *vr_values)
+	       range_query *query)
 {
   /* The type of the result.  */
   const_tree type = integer_type_node;
@@ -1067,10 +1074,11 @@ get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
 	  && TYPE_PRECISION (argtype) <= TYPE_PRECISION (type))
 	{
 	  /* Try to determine the range of values of the integer argument.  */
-	  const value_range_equiv *vr
-	    = CONST_CAST (class vr_values *, vr_values)->get_value_range (arg);
+	  value_range vr;
+	  if (!query->range_of_expr (vr, arg, stmt))
+	    vr.set_varying (TREE_TYPE (arg));
 
-	  if (!vr->undefined_p () && !vr->varying_p () && !vr->symbolic_p ())
+	  if (!vr.undefined_p () && !vr.varying_p ())
 	    {
 	      HOST_WIDE_INT type_min
 		= (TYPE_UNSIGNED (argtype)
@@ -1080,8 +1088,8 @@ get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
 	      HOST_WIDE_INT type_max = tree_to_uhwi (TYPE_MAX_VALUE (argtype));
 
 	      tree type = TREE_TYPE (arg);
-	      tree tmin = wide_int_to_tree (type, vr->lower_bound ());
-	      tree tmax = wide_int_to_tree (type, vr->upper_bound ());
+	      tree tmin = wide_int_to_tree (type, vr.lower_bound ());
+	      tree tmax = wide_int_to_tree (type, vr.upper_bound ());
 	      *pmin = TREE_INT_CST_LOW (tmin);
 	      *pmax = TREE_INT_CST_LOW (tmax);
 
@@ -1103,8 +1111,8 @@ get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
       /* Handle an argument with an unknown range as if none had been
 	 provided.  */
       if (unknown)
-	return get_int_range (NULL_TREE, pmin, pmax, absolute,
-			      negbound, vr_values);
+	return get_int_range (NULL_TREE, NULL, pmin, pmax, absolute,
+			      negbound, query);
     }
 
   /* Adjust each bound as specified by ABSOLUTE and NEGBOUND.  */
@@ -1189,7 +1197,8 @@ adjust_range_for_overflow (tree dirtype, tree *argmin, tree *argmax)
    used when the directive argument or its value isn't known.  */
 
 static fmtresult
-format_integer (const directive &dir, tree arg, const vr_values *vr_values)
+format_integer (gimple *stmt, const directive &dir, tree arg,
+		range_query *query)
 {
   tree intmax_type_node;
   tree uintmax_type_node;
@@ -1372,13 +1381,14 @@ format_integer (const directive &dir, tree arg, const vr_values *vr_values)
     {
       /* Try to determine the range of values of the integer argument
 	 (range information is not available for pointers).  */
-      const value_range_equiv *vr
-	= CONST_CAST (class vr_values *, vr_values)->get_value_range (arg);
+      value_range vr;
+      if (!query->range_of_expr (vr, arg, stmt))
+	vr.set_varying (TREE_TYPE (arg));
 
-      if (!vr->varying_p () && !vr->undefined_p () && !vr->symbolic_p ())
+      if (!vr.varying_p () && !vr.undefined_p ())
 	{
-	  argmin = wide_int_to_tree (TREE_TYPE (arg), vr->lower_bound ());
-	  argmax = wide_int_to_tree (TREE_TYPE (arg), vr->upper_bound ());
+	  argmin = wide_int_to_tree (TREE_TYPE (arg), vr.lower_bound ());
+	  argmax = wide_int_to_tree (TREE_TYPE (arg), vr.upper_bound ());
 
 	  /* Set KNOWNRANGE if the argument is in a known subrange
 	     of the directive's type and neither width nor precision
@@ -1404,7 +1414,7 @@ format_integer (const directive &dir, tree arg, const vr_values *vr_values)
 	      if (code == INTEGER_CST)
 		{
 		  arg = gimple_assign_rhs1 (def);
-		  return format_integer (dir, arg, vr_values);
+		  return format_integer (def, dir, arg, query);
 		}
 
 	      if (code == NOP_EXPR)
@@ -1449,16 +1459,16 @@ format_integer (const directive &dir, tree arg, const vr_values *vr_values)
       /* For unsigned conversions/directives or signed when
 	 the minimum is positive, use the minimum and maximum to compute
 	 the shortest and longest output, respectively.  */
-      res.range.min = format_integer (dir, argmin, vr_values).range.min;
-      res.range.max = format_integer (dir, argmax, vr_values).range.max;
+      res.range.min = format_integer (stmt, dir, argmin, query).range.min;
+      res.range.max = format_integer (stmt, dir, argmax, query).range.max;
     }
   else if (tree_int_cst_sgn (argmax) < 0)
     {
       /* For signed conversions/directives if maximum is negative,
 	 use the minimum as the longest output and maximum as the
 	 shortest output.  */
-      res.range.min = format_integer (dir, argmax, vr_values).range.min;
-      res.range.max = format_integer (dir, argmin, vr_values).range.max;
+      res.range.min = format_integer (stmt, dir, argmax, query).range.min;
+      res.range.max = format_integer (stmt, dir, argmin, query).range.max;
     }
   else
     {
@@ -1467,11 +1477,11 @@ format_integer (const directive &dir, tree arg, const vr_values *vr_values)
 	 length of the output of both minimum and maximum and pick the
 	 longer.  */
       unsigned HOST_WIDE_INT max1
-	= format_integer (dir, argmin, vr_values).range.max;
+	= format_integer (stmt, dir, argmin, query).range.max;
       unsigned HOST_WIDE_INT max2
-	= format_integer (dir, argmax, vr_values).range.max;
+	= format_integer (stmt, dir, argmax, query).range.max;
       res.range.min
-	= format_integer (dir, integer_zero_node, vr_values).range.min;
+	= format_integer (stmt, dir, integer_zero_node, query).range.min;
       res.range.max = MAX (max1, max2);
     }
 
@@ -1820,7 +1830,7 @@ format_floating (const directive &dir, const HOST_WIDE_INT prec[2])
    ARG.  */
 
 static fmtresult
-format_floating (const directive &dir, tree arg, const vr_values *)
+format_floating (gimple *, const directive &dir, tree arg, range_query *)
 {
   HOST_WIDE_INT prec[] = { dir.prec[0], dir.prec[1] };
   tree type = (dir.modifier == FMT_LEN_L || dir.modifier == FMT_LEN_ll
@@ -2014,7 +2024,8 @@ format_floating (const directive &dir, tree arg, const vr_values *)
    Used by the format_string function below.  */
 
 static fmtresult
-get_string_length (tree str, unsigned eltsize, const vr_values *vr)
+get_string_length (tree str, gimple *stmt, unsigned eltsize,
+		   range_query *query)
 {
   if (!str)
     return fmtresult ();
@@ -2025,7 +2036,7 @@ get_string_length (tree str, unsigned eltsize, const vr_values *vr)
   c_strlen_data lendata = { };
   lendata.maxbound = str;
   if (eltsize == 1)
-    get_range_strlen_dynamic (str, &lendata, vr);
+    get_range_strlen_dynamic (str, stmt, &lendata, query);
   else
     {
       /* Determine the length of the shortest and longest string referenced
@@ -2122,7 +2133,8 @@ get_string_length (tree str, unsigned eltsize, const vr_values *vr)
    vsprinf).  */
 
 static fmtresult
-format_character (const directive &dir, tree arg, const vr_values *vr_values)
+format_character (gimple *stmt, const directive &dir, tree arg,
+		  range_query *query)
 {
   fmtresult res;
 
@@ -2135,7 +2147,7 @@ format_character (const directive &dir, tree arg, const vr_values *vr_values)
       res.range.min = 0;
 
       HOST_WIDE_INT min, max;
-      if (get_int_range (arg, &min, &max, false, 0, vr_values))
+      if (get_int_range (arg, stmt, &min, &max, false, 0, query))
 	{
 	  if (min == 0 && max == 0)
 	    {
@@ -2433,7 +2445,8 @@ alias_offset (tree arg, tree dst, HOST_WIDE_INT dst_fld)
    vsprinf).  */
 
 static fmtresult
-format_string (const directive &dir, tree arg, const vr_values *vr_values)
+format_string (gimple *stmt, const directive &dir, tree arg,
+	       range_query *query)
 {
   fmtresult res;
 
@@ -2462,7 +2475,7 @@ format_string (const directive &dir, tree arg, const vr_values *vr_values)
       gcc_checking_assert (count_by == 2 || count_by == 4);
     }
 
-  fmtresult slen = get_string_length (arg, count_by, vr_values);
+  fmtresult slen = get_string_length (arg, stmt, count_by, query);
   if (slen.range.min == slen.range.max
       && slen.range.min < HOST_WIDE_INT_MAX)
     {
@@ -2634,7 +2647,7 @@ format_string (const directive &dir, tree arg, const vr_values *vr_values)
 /* Format plain string (part of the format string itself).  */
 
 static fmtresult
-format_plain (const directive &dir, tree, const vr_values *)
+format_plain (gimple *, const directive &dir, tree, range_query *)
 {
   fmtresult res (dir.len);
   return res;
@@ -3030,7 +3043,7 @@ bytes_remaining (unsigned HOST_WIDE_INT navail, const format_result &res)
 static bool
 format_directive (const call_info &info,
 		  format_result *res, const directive &dir,
-		  const class vr_values *vr_values)
+		  range_query *query)
 {
   /* Offset of the beginning of the directive from the beginning
      of the format string.  */
@@ -3055,7 +3068,7 @@ format_directive (const call_info &info,
     return false;
 
   /* Compute the range of lengths of the formatted output.  */
-  fmtresult fmtres = dir.fmtfunc (dir, dir.arg, vr_values);
+  fmtresult fmtres = dir.fmtfunc (info.callstmt, dir, dir.arg, query);
 
   /* Record whether the output of all directives is known to be
      bounded by some maximum, implying that their arguments are
@@ -3386,7 +3399,7 @@ static size_t
 parse_directive (call_info &info,
 		 directive &dir, format_result *res,
 		 const char *str, unsigned *argno,
-		 const vr_values *vr_values)
+		 range_query *query)
 {
   const char *pcnt = strchr (str, target_percent);
   dir.beg = str;
@@ -3711,7 +3724,7 @@ parse_directive (call_info &info,
   if (star_width)
     {
       if (INTEGRAL_TYPE_P (TREE_TYPE (star_width)))
-	dir.set_width (star_width, vr_values);
+	dir.set_width (star_width, query);
       else
 	{
 	  /* Width specified by a va_list takes on the range [0, -INT_MIN]
@@ -3744,7 +3757,7 @@ parse_directive (call_info &info,
   if (star_precision)
     {
       if (INTEGRAL_TYPE_P (TREE_TYPE (star_precision)))
-	dir.set_precision (star_precision, vr_values);
+	dir.set_precision (star_precision, query);
       else
 	{
 	  /* Precision specified by a va_list takes on the range [-1, INT_MAX]
@@ -3958,7 +3971,8 @@ maybe_warn_overlap (call_info &info, format_result *res)
    that caused the processing to be terminated early).  */
 
 static bool
-compute_format_length (call_info &info, format_result *res, const vr_values *vr)
+compute_format_length (call_info &info, format_result *res,
+		       range_query *query)
 {
   if (dump_file)
     {
@@ -3995,10 +4009,10 @@ compute_format_length (call_info &info, format_result *res, const vr_values *vr)
     {
       directive dir (&info, dirno);
 
-      size_t n = parse_directive (info, dir, res, pf, &argno, vr);
+      size_t n = parse_directive (info, dir, res, pf, &argno, query);
 
       /* Return failure if the format function fails.  */
-      if (!format_directive (info, res, dir, vr))
+      if (!format_directive (info, res, dir, query))
 	return false;
 
       /* Return success when the directive is zero bytes long and it's
@@ -4288,13 +4302,14 @@ get_user_idx_format (tree fndecl, unsigned *idx_args)
    gsi_next should not be performed in the caller.  */
 
 bool
-handle_printf_call (gimple_stmt_iterator *gsi, const vr_values *vr_values)
+handle_printf_call (gimple_stmt_iterator *gsi, range_query *query)
 {
   init_target_to_host_charmap ();
 
   call_info info = call_info ();
 
-  info.callstmt = gsi_stmt (*gsi);
+  gimple *stmt = gsi_stmt (*gsi);
+  info.callstmt = stmt;
   info.func = gimple_call_fndecl (info.callstmt);
   if (!info.func)
     return false;
@@ -4557,14 +4572,15 @@ handle_printf_call (gimple_stmt_iterator *gsi, const vr_values *vr_values)
 	  /* Try to determine the range of values of the argument
 	     and use the greater of the two at level 1 and the smaller
 	     of them at level 2.  */
-	  const value_range_equiv *vr
-	    = CONST_CAST (class vr_values *, vr_values)->get_value_range (size);
+	  value_range vr;
+	  if (!query->range_of_expr (vr, size, stmt))
+	    vr.set_varying (TREE_TYPE (size));
 
-	  if (!vr->undefined_p () && !vr->symbolic_p ())
+	  if (!vr.undefined_p ())
 	    {
 	      tree type = TREE_TYPE (size);
-	      tree tmin = wide_int_to_tree (type, vr->lower_bound ());
-	      tree tmax = wide_int_to_tree (type, vr->upper_bound ());
+	      tree tmin = wide_int_to_tree (type, vr.lower_bound ());
+	      tree tmax = wide_int_to_tree (type, vr.upper_bound ());
 	      unsigned HOST_WIDE_INT minsize = TREE_INT_CST_LOW (tmin);
 	      unsigned HOST_WIDE_INT maxsize = TREE_INT_CST_LOW (tmax);
 	      dstsize = warn_level < 2 ? maxsize : minsize;
@@ -4675,7 +4691,7 @@ handle_printf_call (gimple_stmt_iterator *gsi, const vr_values *vr_values)
      never set to true again).  */
   res.posunder4k = posunder4k && dstptr;
 
-  bool success = compute_format_length (info, &res, vr_values);
+  bool success = compute_format_length (info, &res, query);
   if (res.warned)
     gimple_set_no_warning (info.callstmt, true);
 
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 9907cc0c824..8f2413de3ff 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -200,7 +200,8 @@ static void handle_builtin_stxncpy_strncat (bool, gimple_stmt_iterator *);
    to determine the range, otherwise get_range_info.  */
 
 tree
-get_range (tree val, wide_int minmax[2], const vr_values *rvals /* = NULL */)
+get_range (tree val, gimple *stmt, wide_int minmax[2],
+	   range_query *rvals /* = NULL */)
 {
   if (TREE_CODE (val) == INTEGER_CST)
     {
@@ -211,21 +212,17 @@ get_range (tree val, wide_int minmax[2], const vr_values *rvals /* = NULL */)
   if (TREE_CODE (val) != SSA_NAME)
     return NULL_TREE;
 
-  if (rvals)
-    {
-      /* The range below may be "inaccurate" if a constant has been
-	 substituted earlier for VAL by this pass that hasn't been
-	 propagated through the CFG.  This shoud be fixed by the new
-	 on-demand VRP if/when it becomes available (hopefully in
-	 GCC 11).  */
-      const value_range *vr
-	= (CONST_CAST (class vr_values *, rvals)->get_value_range (val));
-      value_range_kind rng = vr->kind ();
-      if (rng != VR_RANGE || !range_int_cst_p (vr))
+  if (rvals && stmt)
+    {
+      value_range vr;
+      if (!rvals->range_of_expr (vr, val, stmt))
+	return NULL_TREE;
+      value_range_kind rng = vr.kind ();
+      if (rng != VR_RANGE)
 	return NULL_TREE;
 
-      minmax[0] = wi::to_wide (vr->min ());
-      minmax[1] = wi::to_wide (vr->max ());
+      minmax[0] = wi::to_wide (vr.min ());
+      minmax[1] = wi::to_wide (vr.max ());
       return val;
     }
 
@@ -263,7 +260,7 @@ compare_nonzero_chars (strinfo *si, unsigned HOST_WIDE_INT off)
 
 static int
 compare_nonzero_chars (strinfo *si, unsigned HOST_WIDE_INT off,
-		       const vr_values *rvals)
+		       range_query *rvals)
 {
   if (!si->nonzero_chars)
     return -1;
@@ -274,20 +271,19 @@ compare_nonzero_chars (strinfo *si, unsigned HOST_WIDE_INT off,
   if (!rvals || TREE_CODE (si->nonzero_chars) != SSA_NAME)
     return -1;
 
-  const value_range_equiv *vr
-    = (CONST_CAST (class vr_values *, rvals)
-       ->get_value_range (si->nonzero_chars));
-
-  value_range_kind rng = vr->kind ();
-  if (rng != VR_RANGE || !range_int_cst_p (vr))
+  value_range vr;
+  if (!rvals->range_of_expr (vr, si->nonzero_chars, si->stmt))
+    return -1;
+  value_range_kind rng = vr.kind ();
+  if (rng != VR_RANGE)
     return -1;
 
   /* If the offset is less than the minimum length or if the bounds
      of the length range are equal return the result of the comparison
      same as in the constant case.  Otherwise return a conservative
      result.  */
-  int cmpmin = compare_tree_int (vr->min (), off);
-  if (cmpmin > 0 || tree_int_cst_equal (vr->min (), vr->max ()))
+  int cmpmin = compare_tree_int (vr.min (), off);
+  if (cmpmin > 0 || tree_int_cst_equal (vr.min (), vr.max ()))
     return cmpmin;
 
   return -1;
@@ -332,7 +328,7 @@ get_next_strinfo (strinfo *si)
 
 static int
 get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out,
-		 const vr_values *rvals = NULL)
+		 range_query *rvals = NULL)
 {
   HOST_WIDE_INT off;
   struct stridxlist *list, *last = NULL;
@@ -392,7 +388,7 @@ get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out,
    When nonnull, uses RVALS to determine range information.  */
 
 static int
-get_stridx (tree exp, wide_int offrng[2] = NULL, const vr_values *rvals = NULL)
+get_stridx (tree exp, wide_int offrng[2] = NULL, range_query *rvals = NULL)
 {
   if (offrng)
     offrng[0] = offrng[1] = wi::zero (TYPE_PRECISION (ptrdiff_type_node));
@@ -474,7 +470,7 @@ get_stridx (tree exp, wide_int offrng[2] = NULL, const vr_values *rvals = NULL)
 		       return the index corresponding to the SSA_NAME.
 		       Do this irrespective of the whether the offset
 		       is known.  */
-		    if (get_range (off, offrng, rvals))
+		    if (get_range (off, def_stmt, offrng, rvals))
 		      {
 			/* When the offset range is known, increment it
 			   it by the constant offset computed in prior
@@ -864,11 +860,11 @@ get_string_length (strinfo *si)
 }
 
 /* Dump strlen data to FP for statement STMT.  When non-null, RVALS
-   points to EVRP info and is used to dump strlen range for non-constant
-   results.  */
+   points to the valuation engine used to calculate ranges, and is
+   used to dump strlen range for non-constant results.  */
 
 DEBUG_FUNCTION void
-dump_strlen_info (FILE *fp, gimple *stmt, const vr_values *rvals)
+dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals)
 {
   if (stmt)
     {
@@ -909,14 +905,15 @@ dump_strlen_info (FILE *fp, gimple *stmt, const vr_values *rvals)
 		      wide_int min, max;
 		      if (rvals)
 			{
-			  const value_range *vr
-			    = CONST_CAST (class vr_values *, rvals)
-			    ->get_value_range (si->nonzero_chars);
-			  rng = vr->kind ();
-			  if (range_int_cst_p (vr))
+			  value_range vr;
+			  if (!rvals->range_of_expr (vr, si->nonzero_chars,
+						     si->stmt))
+			    vr.set_varying (TREE_TYPE (si->nonzero_chars));
+			  rng = vr.kind ();
+			  if (range_int_cst_p (&vr))
 			    {
-			      min = wi::to_wide (vr->min ());
-			      max = wi::to_wide (vr->max ());
+			      min = wi::to_wide (vr.min ());
+			      max = wi::to_wide (vr.max ());
 			    }
 			  else
 			    rng = VR_UNDEFINED;
@@ -1004,13 +1001,14 @@ dump_strlen_info (FILE *fp, gimple *stmt, const vr_values *rvals)
 
 /* Attempt to determine the length of the string SRC.  On success, store
    the length in *PDATA and return true.  Otherwise, return false.
-   VISITED is a bitmap of visited PHI nodes.  RVALS points to EVRP info
-   and PSSA_DEF_MAX to an SSA_NAME assignment limit used to prevent runaway
-   recursion.  */
+   VISITED is a bitmap of visited PHI nodes.  RVALS points to the valuation
+   engine used to calculate ranges.  PSSA_DEF_MAX to an SSA_NAME
+   assignment limit used to prevent runaway recursion.  */
 
 static bool
-get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited,
-			  const vr_values *rvals, unsigned *pssa_def_max)
+get_range_strlen_dynamic (tree src, gimple *stmt,
+			  c_strlen_data *pdata, bitmap *visited,
+			  range_query *rvals, unsigned *pssa_def_max)
 {
   int idx = get_stridx (src);
   if (!idx)
@@ -1042,8 +1040,8 @@ get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited,
 		    continue;
 
 		  c_strlen_data argdata = { };
-		  if (get_range_strlen_dynamic (arg, &argdata, visited, rvals,
-						pssa_def_max))
+		  if (get_range_strlen_dynamic (arg, phi, &argdata, visited,
+						rvals, pssa_def_max))
 		    {
 		      /* Set the DECL of an unterminated array this argument
 			 refers to if one hasn't been found yet.  */
@@ -1110,14 +1108,13 @@ get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited,
 	    pdata->minlen = si->nonzero_chars;
 	  else if (TREE_CODE (si->nonzero_chars) == SSA_NAME)
 	    {
-	      const value_range_equiv *vr
-		= CONST_CAST (class vr_values *, rvals)
-		->get_value_range (si->nonzero_chars);
-	      if (vr->kind () == VR_RANGE
-		  && range_int_cst_p (vr))
+	      value_range vr;
+	      if (!rvals->range_of_expr (vr, si->nonzero_chars, si->stmt))
+		vr.set_varying (TREE_TYPE (si->nonzero_chars));
+	      if (range_int_cst_p (&vr))
 		{
-		  pdata->minlen = vr->min ();
-		  pdata->maxlen = vr->max ();
+		  pdata->minlen = vr.min ();
+		  pdata->maxlen = vr.max ();
 		}
 	      else
 		pdata->minlen = build_zero_cst (size_type_node);
@@ -1156,14 +1153,13 @@ get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited,
 	}
       else if (pdata->minlen && TREE_CODE (pdata->minlen) == SSA_NAME)
 	{
-	  const value_range_equiv *vr
-	    = CONST_CAST (class vr_values *, rvals)
-	    ->get_value_range (si->nonzero_chars);
-	  if (vr->kind () == VR_RANGE
-	      && range_int_cst_p (vr))
+	  value_range vr;
+	  if (!rvals->range_of_expr (vr, si->nonzero_chars, stmt))
+	    vr.set_varying (TREE_TYPE (si->nonzero_chars));
+	  if (range_int_cst_p (&vr))
 	    {
-	      pdata->minlen = vr->min ();
-	      pdata->maxlen = vr->max ();
+	      pdata->minlen = vr.min ();
+	      pdata->maxlen = vr.max ();
 	      pdata->maxbound = pdata->maxlen;
 	    }
 	  else
@@ -1198,17 +1194,17 @@ get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited,
    Try to obtain the range of the lengths of the string(s) referenced
    by SRC, or the size of the largest array SRC refers to if the range
    of lengths cannot be determined, and store all in *PDATA.  RVALS
-   points to EVRP info.  */
+   points to the valuation engine used to calculate ranges.  */
 
 void
-get_range_strlen_dynamic (tree src, c_strlen_data *pdata,
-			  const vr_values *rvals)
+get_range_strlen_dynamic (tree src, gimple *stmt, c_strlen_data *pdata,
+			  range_query *rvals)
 {
   bitmap visited = NULL;
   tree maxbound = pdata->maxbound;
 
   unsigned limit = param_ssa_name_def_chain_limit;
-  if (!get_range_strlen_dynamic (src, pdata, &visited, rvals, &limit))
+  if (!get_range_strlen_dynamic (src, stmt, pdata, &visited, rvals, &limit))
     {
       /* On failure extend the length range to an impossible maximum
 	 (a valid MAXLEN must be less than PTRDIFF_MAX - 1).  Other
@@ -1803,6 +1799,7 @@ 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)
 	    {
@@ -1907,7 +1904,7 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
 
 static void
 maybe_warn_overflow (gimple *stmt, tree len,
-		     const vr_values *rvals = NULL,
+		     range_query *rvals = NULL,
 		     strinfo *si = NULL, bool plus_one = false,
 		     bool rawmem = false)
 {
@@ -1959,7 +1956,7 @@ maybe_warn_overflow (gimple *stmt, tree len,
 	  tree off = TREE_OPERAND (ref, 1);
 	  ref = TREE_OPERAND (ref, 0);
 	  wide_int rng[2];
-	  if (get_range (off, rng, rvals))
+	  if (get_range (off, stmt, rng, rvals))
 	    {
 	      /* Convert offsets to the maximum precision.  */
 	      offrng[0] = widest_int::from (rng[0], SIGNED);
@@ -1977,7 +1974,7 @@ maybe_warn_overflow (gimple *stmt, tree len,
 	  tree mem_off = TREE_OPERAND (ref, 1);
 	  ref = TREE_OPERAND (ref, 0);
 	  wide_int rng[2];
-	  if (get_range (mem_off, rng, rvals))
+	  if (get_range (mem_off, stmt, rng, rvals))
 	    {
 	      offrng[0] += widest_int::from (rng[0], SIGNED);
 	      offrng[1] += widest_int::from (rng[1], SIGNED);
@@ -2049,7 +2046,7 @@ maybe_warn_overflow (gimple *stmt, tree len,
 	    }
 
 	  wide_int rng[2];
-	  if (get_range (destsize, rng, rvals))
+	  if (get_range (destsize, stmt, rng, rvals))
 	    {
 	      sizrng[0] = widest_int::from (rng[0], UNSIGNED);
 	      sizrng[1] = widest_int::from (rng[1], UNSIGNED);
@@ -2080,7 +2077,7 @@ maybe_warn_overflow (gimple *stmt, tree len,
     return;
 
   wide_int rng[2];
-  if (!get_range (len, rng, rvals))
+  if (!get_range (len, stmt, rng, rvals))
     return;
 
   widest_int lenrng[2] =
@@ -2231,7 +2228,7 @@ maybe_warn_overflow (gimple *stmt, tree len,
   if (destoff)
     {
       wide_int rng[2];
-      if (get_range (destoff, rng))
+      if (get_range (destoff, stmt, rng))
 	{
 	  offrng[0] = widest_int::from (rng[0], SIGNED);
 	  offrng[1] = widest_int::from (rng[1], SIGNED);
@@ -2339,7 +2336,7 @@ maybe_warn_overflow (gimple *stmt, tree len,
 
 static inline void
 maybe_warn_overflow (gimple *stmt, unsigned HOST_WIDE_INT len,
-		     const vr_values *rvals = NULL, strinfo *si = NULL,
+		     range_query *rvals = NULL, strinfo *si = NULL,
 		     bool plus_one = false, bool rawmem = false)
 {
   maybe_warn_overflow (stmt, build_int_cst (size_type_node, len), rvals,
@@ -2642,7 +2639,7 @@ handle_builtin_strchr (gimple_stmt_iterator *gsi)
 
 static void
 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi,
-		       const vr_values *rvals)
+		       range_query *rvals)
 {
   int idx, didx;
   tree src, dst, srclen, len, lhs, type, fn, oldlen;
@@ -3036,6 +3033,7 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
     cntrange[0] = cntrange[1] = wi::to_wide (cnt);
   else if (TREE_CODE (cnt) == SSA_NAME)
     {
+      // FIXME: Use range_query instead of global ranges.
       enum value_range_kind rng = get_range_info (cnt, cntrange, cntrange + 1);
       if (rng == VR_RANGE)
 	;
@@ -3444,7 +3442,7 @@ handle_builtin_stxncpy_strncat (bool append_p, gimple_stmt_iterator *gsi)
 
 static void
 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi,
-		       const vr_values *rvals)
+		       range_query *rvals)
 {
   tree lhs, oldlen, newlen;
   gimple *stmt = gsi_stmt (*gsi);
@@ -3909,7 +3907,7 @@ handle_alloc_call (enum built_in_function bcode, gimple_stmt_iterator *gsi)
 
 static bool
 handle_builtin_memset (gimple_stmt_iterator *gsi, bool *zero_write,
-		       const vr_values *rvals)
+		       range_query *rvals)
 {
   gimple *memset_stmt = gsi_stmt (*gsi);
   tree ptr = gimple_call_arg (memset_stmt, 0);
@@ -4103,9 +4101,10 @@ handle_builtin_memcmp (gimple_stmt_iterator *gsi)
    determine range information. Returns true on success.  */
 
 static bool
-get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
+get_len_or_size (gimple *stmt, tree arg, int idx,
+		 unsigned HOST_WIDE_INT lenrng[2],
 		 unsigned HOST_WIDE_INT *size, bool *nulterm,
-		 const vr_values *rvals)
+		 range_query *rvals)
 {
   /* Invalidate.  */
   *size = HOST_WIDE_INT_M1U;
@@ -4140,6 +4139,7 @@ get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
       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)
 	    {
@@ -4158,7 +4158,7 @@ get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
   /* Set MAXBOUND to an arbitrary non-null non-integer node as a request
      to have it set to the length of the longest string in a PHI.  */
   lendata.maxbound = arg;
-  get_range_strlen_dynamic (arg, &lendata, rvals);
+  get_range_strlen_dynamic (arg, stmt, &lendata, rvals);
 
   unsigned HOST_WIDE_INT maxbound = HOST_WIDE_INT_M1U;
   if (tree_fits_uhwi_p (lendata.maxbound)
@@ -4216,17 +4216,17 @@ get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
    Otherwise return null.  */
 
 static tree
-strxcmp_eqz_result (tree arg1, int idx1, tree arg2, int idx2,
+strxcmp_eqz_result (gimple *stmt, tree arg1, int idx1, tree arg2, int idx2,
 		    unsigned HOST_WIDE_INT bound, unsigned HOST_WIDE_INT len[2],
-		    unsigned HOST_WIDE_INT *psize, const vr_values *rvals)
+		    unsigned HOST_WIDE_INT *psize, range_query *rvals)
 {
   /* Determine the range the length of each string is in and whether it's
      known to be nul-terminated, or the size of the array it's stored in.  */
   bool nul1, nul2;
   unsigned HOST_WIDE_INT siz1, siz2;
   unsigned HOST_WIDE_INT len1rng[2], len2rng[2];
-  if (!get_len_or_size (arg1, idx1, len1rng, &siz1, &nul1, rvals)
-      || !get_len_or_size (arg2, idx2, len2rng, &siz2, &nul2, rvals))
+  if (!get_len_or_size (stmt, arg1, idx1, len1rng, &siz1, &nul1, rvals)
+      || !get_len_or_size (stmt, arg2, idx2, len2rng, &siz2, &nul2, rvals))
     return NULL_TREE;
 
   /* BOUND is set to HWI_M1U for strcmp and less to strncmp, and LENiRNG
@@ -4375,7 +4375,7 @@ maybe_warn_pointless_strcmp (gimple *stmt, HOST_WIDE_INT bound,
    another and false otherwise.  */
 
 static bool
-handle_builtin_string_cmp (gimple_stmt_iterator *gsi, const vr_values *rvals)
+handle_builtin_string_cmp (gimple_stmt_iterator *gsi, range_query *rvals)
 {
   gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
   tree lhs = gimple_call_lhs (stmt);
@@ -4420,7 +4420,7 @@ handle_builtin_string_cmp (gimple_stmt_iterator *gsi, const vr_values *rvals)
     /* Try to determine if the two strings are either definitely equal
        or definitely unequal and if so, either fold the result to zero
        (when equal) or set the range of the result to ~[0, 0] otherwise.  */
-    if (tree eqz = strxcmp_eqz_result (arg1, idx1, arg2, idx2, bound,
+    if (tree eqz = strxcmp_eqz_result (stmt, arg1, idx1, arg2, idx2, bound,
 				       len, &siz, rvals))
       {
 	if (integer_zerop (eqz))
@@ -4457,8 +4457,9 @@ handle_builtin_string_cmp (gimple_stmt_iterator *gsi, const vr_values *rvals)
     unsigned HOST_WIDE_INT arsz1, arsz2;
     bool nulterm[2];
 
-    if (!get_len_or_size (arg1, idx1, len1rng, &arsz1, nulterm, rvals)
-	|| !get_len_or_size (arg2, idx2, len2rng, &arsz2, nulterm + 1, rvals))
+    if (!get_len_or_size (stmt, arg1, idx1, len1rng, &arsz1, nulterm, rvals)
+	|| !get_len_or_size (stmt, arg2, idx2, len2rng, &arsz2, nulterm + 1,
+			     rvals))
       return false;
 
     if (len1rng[0] == len1rng[1] && len1rng[0] < HOST_WIDE_INT_MAX)
@@ -4623,7 +4624,7 @@ int ssa_name_limit_t::next_ssa_name (tree ssa_name)
 static bool
 count_nonzero_bytes_addr (tree, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
 			  unsigned [3], bool *, bool *, bool *,
-			  const vr_values *, ssa_name_limit_t &);
+			  range_query *, ssa_name_limit_t &);
 
 /* Determines the minimum and maximum number of leading non-zero bytes
    in the representation of EXP and set LENRANGE[0] and LENRANGE[1]
@@ -4644,7 +4645,7 @@ static bool
 count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
 		     unsigned HOST_WIDE_INT nbytes,
 		     unsigned lenrange[3], bool *nulterm,
-		     bool *allnul, bool *allnonnul, const vr_values *rvals,
+		     bool *allnul, bool *allnonnul, range_query *rvals,
 		     ssa_name_limit_t &snlim)
 {
   if (TREE_CODE (exp) == SSA_NAME)
@@ -4836,7 +4837,7 @@ count_nonzero_bytes_addr (tree exp, unsigned HOST_WIDE_INT offset,
 			  unsigned HOST_WIDE_INT nbytes,
 			  unsigned lenrange[3], bool *nulterm,
 			  bool *allnul, bool *allnonnul,
-			  const vr_values *rvals, ssa_name_limit_t &snlim)
+			  range_query *rvals, ssa_name_limit_t &snlim)
 {
   int idx = get_stridx (exp);
   if (idx > 0)
@@ -4853,13 +4854,14 @@ count_nonzero_bytes_addr (tree exp, unsigned HOST_WIDE_INT offset,
       else if (si->nonzero_chars
 	       && TREE_CODE (si->nonzero_chars) == SSA_NAME)
 	{
-	  vr_values *v = CONST_CAST (vr_values *, rvals);
-	  const value_range_equiv *vr = v->get_value_range (si->nonzero_chars);
-	  if (vr->kind () != VR_RANGE || !range_int_cst_p (vr))
+	  value_range vr;
+	  if (!rvals->range_of_expr (vr, si->nonzero_chars, si->stmt))
+	    vr.set_varying (TREE_TYPE (si->nonzero_chars));
+	  if (vr.kind () != VR_RANGE)
 	    return false;
 
-	  minlen = tree_to_uhwi (vr->min ());
-	  maxlen = tree_to_uhwi (vr->max ());
+	  minlen = tree_to_uhwi (vr.min ());
+	  maxlen = tree_to_uhwi (vr.max ());
 	}
       else
 	return false;
@@ -4948,7 +4950,7 @@ count_nonzero_bytes_addr (tree exp, unsigned HOST_WIDE_INT offset,
 
 static bool
 count_nonzero_bytes (tree exp, unsigned lenrange[3], bool *nulterm,
-		     bool *allnul, bool *allnonnul, const vr_values *rvals)
+		     bool *allnul, bool *allnonnul, range_query *rvals)
 {
   /* Set to optimistic values so the caller doesn't have to worry about
      initializing these and to what.  On success, the function will clear
@@ -4972,7 +4974,7 @@ count_nonzero_bytes (tree exp, unsigned lenrange[3], bool *nulterm,
 
 static bool
 handle_store (gimple_stmt_iterator *gsi, bool *zero_write,
-	      const vr_values *rvals)
+	      range_query *rvals)
 {
   int idx = -1;
   strinfo *si = NULL;
@@ -5382,7 +5384,7 @@ is_char_type (tree type)
 
 static bool
 strlen_check_and_optimize_call (gimple_stmt_iterator *gsi, bool *zero_write,
-				const vr_values *rvals)
+				range_query *rvals)
 {
   gimple *stmt = gsi_stmt (*gsi);
 
@@ -5473,7 +5475,7 @@ strlen_check_and_optimize_call (gimple_stmt_iterator *gsi, bool *zero_write,
 
 static void
 handle_integral_assign (gimple_stmt_iterator *gsi, bool *cleanup_eh,
-			const vr_values *rvals)
+			range_query *rvals)
 {
   gimple *stmt = gsi_stmt (*gsi);
   tree lhs = gimple_assign_lhs (stmt);
@@ -5565,6 +5567,7 @@ handle_integral_assign (gimple_stmt_iterator *gsi, bool *cleanup_eh,
 		  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
@@ -5617,7 +5620,7 @@ handle_integral_assign (gimple_stmt_iterator *gsi, bool *cleanup_eh,
 
 static bool
 check_and_optimize_stmt (gimple_stmt_iterator *gsi, bool *cleanup_eh,
-			 const vr_values *rvals)
+			 range_query *rvals)
 {
   gimple *stmt = gsi_stmt (*gsi);
 
diff --git a/gcc/tree-ssa-strlen.h b/gcc/tree-ssa-strlen.h
index a11c4d579a1..225f64b1630 100644
--- a/gcc/tree-ssa-strlen.h
+++ b/gcc/tree-ssa-strlen.h
@@ -25,13 +25,14 @@ extern bool is_strlen_related_p (tree, tree);
 extern bool maybe_diag_stxncpy_trunc (gimple_stmt_iterator, tree, tree);
 extern tree set_strlen_range (tree, wide_int, wide_int, tree = NULL_TREE);
 
-class vr_values;
-extern tree get_range (tree, wide_int[2], const vr_values * = NULL);
+extern tree get_range (tree, gimple *, wide_int[2],
+		       class range_query * = NULL);
 
 struct c_strlen_data;
-extern void get_range_strlen_dynamic (tree , c_strlen_data *, const vr_values *);
+extern void get_range_strlen_dynamic (tree, gimple *, c_strlen_data *,
+				      class range_query *);
 
 /* APIs internal to strlen pass.  Defined in gimple-ssa-sprintf.c.  */
-extern bool handle_printf_call (gimple_stmt_iterator *,  const vr_values *);
+extern bool handle_printf_call (gimple_stmt_iterator *,  class range_query *);
 
 #endif   // GCC_TREE_SSA_STRLEN_H
-- 
2.26.2


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

end of thread, other threads:[~2020-11-10 14:48 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-18 18:38 [PATCH] generalized range_query class for multiple contexts Aldy Hernandez
2020-09-18 20:40 ` Aldy Hernandez
2020-09-23 23:53 ` Martin Sebor
2020-09-24  6:46   ` Aldy Hernandez
2020-09-24 17:10     ` Martin Sebor
2020-09-25 17:41   ` Andrew MacLeod
2020-09-28 15:27     ` Martin Sebor
2020-09-28 15:48       ` Andrew MacLeod
2020-10-01  4:17     ` Andrew MacLeod
2020-09-24 21:51 ` Martin Sebor
2020-09-25 13:17   ` Andrew MacLeod
2020-09-28  8:12     ` Aldy Hernandez
2020-10-01  9:05   ` Aldy Hernandez
2020-10-01 13:22     ` Andrew MacLeod
2020-10-01 15:34       ` Aldy Hernandez
2020-10-01 17:25         ` Martin Sebor
2020-11-05 19:29           ` Martin Sebor
2020-11-05 21:02             ` Martin Sebor
2020-11-06  0:02               ` Andrew MacLeod
2020-11-06  0:50                 ` Martin Sebor
2020-11-06  3:08                   ` Andrew MacLeod
2020-11-06 16:13                     ` Martin Sebor
2020-11-06 21:54                       ` Andrew MacLeod
2020-11-10 14:48                         ` Martin Sebor
2020-11-06  0:05             ` Andrew MacLeod
2020-11-10  1:57             ` Andrew MacLeod

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