[COMMITTED,2/3] PR tree-optimization/117287 - Reimplement 'assume' processing pass.

Message ID 0b2c27d9-bd13-4c6b-98a1-0f4b22952fb9@redhat.com
State New
Headers
Series [COMMITTED,1/3] Make fur_edge accessible. |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 fail Patch failed to apply
linaro-tcwg-bot/tcwg_gcc_build--master-arm fail Patch failed to apply

Commit Message

Andrew MacLeod Nov. 1, 2024, 7:25 p.m. UTC
  The PR exposed latent issues with the assume pass.  Upon deeper 
investigation, the original approach was a bit naive, and I found other 
flaws. There are numerous changes.

The original mechanism made a single pass working back from the return 
statement. This fails when flow starts to get a bit complicated.  It now 
looks at what the values of the parameters are on EACH path to the 
return statement that results ina TRUE value and combines those.

It also no longer intergrates tightly with ranger components, and 
instead is simply a client pass using the generic range_query API.  AS 
such, I moved all the related code out of tree-vrp.cc and 
gimple-range.cc  and into its own self contained pass file, tree-assume.cc

I put a lot of comments at the top of that file to indicate how assume 
works, and this new algorithm seems to be much more robust the previous 
version.

I wanted to get it in sooner than later so Jakub can work with it to see 
if anything else shows up.   Meanwhile, I will addmore 
diagnostic/debugging abilities as right now its pretty much does its job 
silently, and there is no indication of HOW it determined values  (not 
that there was much before :-)

The new approach uses GORI to determine any ranges in any basic block 
immediately preceeding the return block (including the return block 
itelf), and then invokes ranger for any other ranges feeding that.   Any 
time it cant be sure if an edge is executes or it cant determine 
specific values for any reason, it'll default to a conservative answer 
based on what ranger says.

With more complex flow, I can imagine situations where we are not quite 
as precise as we could be (as in the following patch), but I haven't 
been able to produce one yet that is dependent on more changes to this 
alogithm.  This is certainly better than it was before anyway, and I 
think it should always be correct.

Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew
  

Patch

From 74710442f291902c19b84cebf7642b74ecec8965 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Mon, 28 Oct 2024 10:19:27 -0400
Subject: [PATCH 2/3] Reimplement 'assume' processing pass.

Rework the assume pass to work properly and fail conservatively when it
does.  Also move it to its own file.

	PR tree-optimization/117287
	gcc/
	* Makefile.in (IBJS): Add tree-assume.o
	* gimple-range.cc (assume_query::assume_range_p): Remove.
	(assume_query::range_of_expr): Remove.
	(assume_query::assume_query): Move to tree-assume.cc.
	(assume_query::~assume_query): Remove.
	(assume_query::calculate_op): Move to tree-assume.cc.
	(assume_query::calculate_phi): Likewise.
	(assume_query::check_taken_edge): Remove.
	(assume_query::calculate_stmt): Move to tree-assume.cc.
	(assume_query::dump): Remove.
	* gimple-range.h (class assume_query): Move to tree-assume.cc
	* tree-assume.cc: New
	* tree-vrp.cc (struct pass_data_assumptions): Move to tree-assume.cc.
	(class pass_assumptions): Likewise.
	(make_pass_assumptions): Likewise.

	gcc/testsuite/
	* g++.dg/cpp23/pr117287-attr.C: New.
---
 gcc/Makefile.in                            |   1 +
 gcc/gimple-range.cc                        | 194 -----------
 gcc/gimple-range.h                         |  17 -
 gcc/testsuite/g++.dg/cpp23/pr117287-attr.C |  38 +++
 gcc/tree-assume.cc                         | 369 +++++++++++++++++++++
 gcc/tree-vrp.cc                            |  60 ----
 6 files changed, 408 insertions(+), 271 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp23/pr117287-attr.C
 create mode 100644 gcc/tree-assume.cc

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 1be4ea02992..a1ffc173b97 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1699,6 +1699,7 @@  OBJS = \
 	sanopt.o \
 	sancov.o \
 	simple-diagnostic-path.o \
+	tree-assume.o \
 	tree-call-cdce.o \
 	tree-cfg.o \
 	tree-cfgcleanup.o \
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index f6aa27399a2..00e1a3c4ad5 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -700,200 +700,6 @@  disable_ranger (struct function *fun)
   fun->x_range_query = NULL;
 }
 
-// ------------------------------------------------------------------------
-
-// If there is a non-varying value associated with NAME, return true and the
-// range in R.
-
-bool
-assume_query::assume_range_p (vrange &r, tree name)
-{
-  if (global.get_range (r, name))
-    return !r.varying_p ();
-  return false;
-}
-
-// Query used by GORI to pick up any known value on entry to a block.
-
-bool
-assume_query::range_of_expr (vrange &r, tree expr, gimple *stmt)
-{
-  if (!gimple_range_ssa_p (expr))
-    return get_tree_range (r, expr, stmt);
-
-  if (!global.get_range (r, expr))
-    r.set_varying (TREE_TYPE (expr));
-  return true;
-}
-
-// If the current function returns an integral value, and has a single return
-// statement, it will calculate any SSA_NAMES it can determine ranges for
-// assuming the function returns 1.
-
-assume_query::assume_query ()
-{
-  create_gori (0, param_vrp_switch_limit);
-  basic_block exit_bb = EXIT_BLOCK_PTR_FOR_FN (cfun);
-  if (single_pred_p (exit_bb))
-    {
-      basic_block bb = single_pred (exit_bb);
-      gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
-      if (gsi_end_p (gsi))
-	return;
-      gimple *s = gsi_stmt (gsi);
-      if (!is_a<greturn *> (s))
-	return;
-      greturn *gret = as_a<greturn *> (s);
-      tree op = gimple_return_retval (gret);
-      if (!gimple_range_ssa_p (op))
-	return;
-      tree lhs_type = TREE_TYPE (op);
-      if (!irange::supports_p (lhs_type))
-	return;
-
-      unsigned prec = TYPE_PRECISION (lhs_type);
-      int_range<2> lhs_range (lhs_type, wi::one (prec), wi::one (prec));
-      global.set_range (op, lhs_range);
-
-      gimple *def = SSA_NAME_DEF_STMT (op);
-      if (!def || gimple_get_lhs (def) != op)
-	return;
-      fur_stmt src (gret, this);
-      calculate_stmt (def, lhs_range, src);
-    }
-}
-
-assume_query::~assume_query ()
-{
-  destroy_gori ();
-}
-
-// Evaluate operand OP on statement S, using the provided LHS range.
-// If successful, set the range in the global table, then visit OP's def stmt.
-
-void
-assume_query::calculate_op (tree op, gimple *s, vrange &lhs, fur_source &src)
-{
-  value_range op_range (TREE_TYPE (op));
-  if (gori ().compute_operand_range (op_range, s, lhs, op, src)
-      && !op_range.varying_p ())
-    {
-      // Set the global range, merging if there is already a range.
-      global.merge_range (op, op_range);
-      gimple *def_stmt = SSA_NAME_DEF_STMT (op);
-      if (def_stmt && gimple_get_lhs (def_stmt) == op)
-	calculate_stmt (def_stmt, op_range, src);
-    }
-}
-
-// Evaluate PHI statement, using the provided LHS range.
-// Check each constant argument predecessor if it can be taken
-// provide LHS to any symbolic arguments, and process their def statements.
-
-void
-assume_query::calculate_phi (gphi *phi, vrange &lhs_range, fur_source &src)
-{
-  for (unsigned x= 0; x < gimple_phi_num_args (phi); x++)
-    {
-      tree arg = gimple_phi_arg_def (phi, x);
-      value_range arg_range (TREE_TYPE (arg));
-      if (gimple_range_ssa_p (arg))
-	{
-	  // A symbol arg will be the LHS value.
-	  arg_range = lhs_range;
-	  range_cast (arg_range, TREE_TYPE (arg));
-	  if (!global.get_range (arg_range, arg))
-	    {
-	      global.set_range (arg, arg_range);
-	      gimple *def_stmt = SSA_NAME_DEF_STMT (arg);
-	      if (def_stmt && gimple_get_lhs (def_stmt) == arg)
-		calculate_stmt (def_stmt, arg_range, src);
-	    }
-	}
-      else if (get_tree_range (arg_range, arg, NULL))
-	{
-	  // If this is a constant value that differs from LHS, this
-	  // edge cannot be taken.
-	  arg_range.intersect (lhs_range);
-	  if (arg_range.undefined_p ())
-	    continue;
-	  // Otherwise check the condition feeding this edge.
-	  edge e = gimple_phi_arg_edge (phi, x);
-	  check_taken_edge (e, src);
-	}
-    }
-}
-
-// If an edge is known to be taken, examine the outgoing edge to see
-// if it carries any range information that can also be evaluated.
-
-void
-assume_query::check_taken_edge (edge e, fur_source &src)
-{
-  gimple *stmt = gimple_outgoing_range_stmt_p (e->src);
-  if (stmt && is_a<gcond *> (stmt))
-    {
-      int_range<2> cond;
-      gcond_edge_range (cond, e);
-      calculate_stmt (stmt, cond, src);
-    }
-}
-
-// Evaluate statement S which produces range LHS_RANGE.
-
-void
-assume_query::calculate_stmt (gimple *s, vrange &lhs_range, fur_source &src)
-{
-  gimple_range_op_handler handler (s);
-  if (handler)
-    {
-      tree op = gimple_range_ssa_p (handler.operand1 ());
-      if (op)
-	calculate_op (op, s, lhs_range, src);
-      op = gimple_range_ssa_p (handler.operand2 ());
-      if (op)
-	calculate_op (op, s, lhs_range, src);
-    }
-  else if (is_a<gphi *> (s))
-    {
-      calculate_phi (as_a<gphi *> (s), lhs_range, src);
-      // Don't further check predecessors of blocks with PHIs.
-      return;
-    }
-
-  // Even if the walk back terminates before the top, if this is a single
-  // predecessor block, see if the predecessor provided any ranges to get here.
-  if (single_pred_p (gimple_bb (s)))
-    check_taken_edge (single_pred_edge (gimple_bb (s)), src);
-}
-
-// Show everything that was calculated.
-
-void
-assume_query::dump (FILE *f)
-{
-  fprintf (f, "Assumption details calculated:\n");
-  for (unsigned i = 0; i < num_ssa_names; i++)
-    {
-      tree name = ssa_name (i);
-      if (!name || !gimple_range_ssa_p (name))
-	continue;
-      tree type = TREE_TYPE (name);
-      if (!value_range::supports_type_p (type))
-	continue;
-
-      value_range assume_range (type);
-      if (assume_range_p (assume_range, name))
-	{
-	  print_generic_expr (f, name, TDF_SLIM);
-	  fprintf (f, " -> ");
-	  assume_range.dump (f);
-	  fputc ('\n', f);
-	}
-    }
-  fprintf (f, "------------------------------\n");
-}
-
 // ---------------------------------------------------------------------------
 //
 // The DOM based ranger assumes a single DOM walk through the IL, and is
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index 62bd8a87112..252c2d79d65 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -82,23 +82,6 @@  extern gimple_ranger *enable_ranger (struct function *m,
 				     bool use_imm_uses = true);
 extern void disable_ranger (struct function *);
 
-class assume_query : public range_query
-{
-public:
-  assume_query ();
-  ~assume_query ();
-  bool assume_range_p (vrange &r, tree name);
-  virtual bool range_of_expr (vrange &r, tree expr, gimple * = NULL);
-  void dump (FILE *f);
-protected:
-  void calculate_stmt (gimple *s, vrange &lhs_range, fur_source &src);
-  void calculate_op (tree op, gimple *s, vrange &lhs, fur_source &src);
-  void calculate_phi (gphi *phi, vrange &lhs_range, fur_source &src);
-  void check_taken_edge (edge e, fur_source &src);
-
-  ssa_lazy_cache global;
-};
-
 // DOM based ranger for fast VRP.
 // This must be processed in DOM order, and does only basic range operations.
 
diff --git a/gcc/testsuite/g++.dg/cpp23/pr117287-attr.C b/gcc/testsuite/g++.dg/cpp23/pr117287-attr.C
new file mode 100644
index 00000000000..759c21dc283
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/pr117287-attr.C
@@ -0,0 +1,38 @@ 
+// P1774R8 - Portable assumptions
+// { dg-do run { target c++23 } }
+// { dg-options "-O2 --param=logical-op-non-short-circuit=0" }
+// Test the we can optimize based on conditions in assume.
+
+static inline bool
+foo (unsigned x)
+{
+  return x == 4 || x == 5 || x == 9 || x == 10;
+}
+
+int v;
+
+[[gnu::noipa]] void
+bar (const char *p)
+{
+  if (p[0] != (v ? 'a' : 'b') || p[1])
+    __builtin_abort ();
+}
+
+[[gnu::noipa]] void
+baz (unsigned x)
+{
+  bool a = x == 5;
+  [[assume (foo (x))]];
+  bar (a ? "a" : "b");
+}
+
+int
+main ()
+{
+  baz (4);
+  v = 1;
+  baz (5);
+  v = 0;
+  baz (9);
+  baz (10);
+}
diff --git a/gcc/tree-assume.cc b/gcc/tree-assume.cc
new file mode 100644
index 00000000000..dd279f58179
--- /dev/null
+++ b/gcc/tree-assume.cc
@@ -0,0 +1,369 @@ 
+/* Support for C++23 ASSUME keyword functionailty.
+   Copyright (C) 2023-2024 Free Software Foundation, Inc.
+   Contributed by 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 "basic-block.h"
+#include "bitmap.h"
+#include "options.h"
+#include "function.h"
+#include "cfg.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-iterator.h"
+#include "gimple-range.h"
+#include "tree-dfa.h"
+
+// An assume query utilizes the current range query to implelemtn the assume
+// keyword.
+// For any return value of 1 from the function, it attempts to determine
+// which paths leads to a 1 value being returned. On those paths, what
+// the ranges of any ssa_names listed in bitmap P (usually the parm list for
+// the function) are, and combined them all.
+// These ranges are then set as the global ranges for those parms in this
+// function.
+// Other functions which then refer to this function in an assume builtin
+// will then pick up these ranges for the paramters via the inferred range
+// mechanism.
+//   See gimple-range-infer.cc::gimple_infer_range::check_assume_func ()
+//
+// my_func (int x)
+// {
+//   <...>
+//   assume [[(x == 1 || x ==4))]]
+//   if (x ==3)
+//
+// a small temporary assume function consisting of
+// assume_f1 (int x) { return x == 1 || x == 4; }
+// is constructed by the front end, and optimzed, at the very end of
+// optimization, instead of generating code, we instead invoke the assume pass
+// which uses this query to set the the global value of parm x to [1,1][4,4]
+//
+// Meanwhile., my_Fund has been rewritten to be:
+//
+// my_func (int x_2)
+// {
+//   <...>
+//   assume_builtin_call  assume_f1 (x_2);
+//   if (x_2 == 3)
+//
+// When ranger is processing the assume_builtin_call, it looks up the global
+// value of the paramter in assume_f1, which is [1,1][4,4].  It then registers
+// and inferred range at this statement setting the value x_2 to [1,1][4,4]
+//
+// Any uses of x_2 after this statement will now utilzie this inferred range.
+//
+// When VRP precoesses if (x_2 == 3), it picks up the inferred range, and
+// determines that x_2 can never be 3, and will rewrite the branch to
+//   if (0 != 0)
+
+class assume_query
+{
+public:
+  assume_query (function *f, bitmap p);
+protected:
+  inline void process_stmts (gimple *s, vrange &lhs_range)
+  {
+    fur_depend src (s, get_range_query (m_func));
+    calculate_stmt (s, lhs_range, src);
+    update_parms (src);
+  }
+  void update_parms (fur_source &src);
+  void calculate_stmt (gimple *s, vrange &lhs_range, fur_source &src);
+  void calculate_op (tree op, gimple *s, vrange &lhs, fur_source &src);
+  void calculate_phi (gphi *phi, vrange &lhs_range);
+
+  ssa_lazy_cache m_path;   // Values found on path
+  ssa_lazy_cache m_parms;  // Cumulative parameter value calculated
+  bitmap &m_parm_list;	   // Parameter ssa-names list.
+  function *m_func;
+};
+
+// If function F returns a integral value, and has a single return
+// statement, try to calculate the range of each value in P that leads
+// to the return statement returning TRUE.
+
+assume_query::assume_query (function *f, bitmap p) : m_parm_list (p),
+						     m_func (f)
+{
+  basic_block exit_bb = EXIT_BLOCK_PTR_FOR_FN (f);
+  // If there is more than one precessor to the exit block, bail.
+  if (!single_pred_p (exit_bb))
+    return;
+
+  basic_block bb = single_pred (exit_bb);
+  gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
+  if (gsi_end_p (gsi))
+    return;
+  gimple *s = gsi_stmt (gsi);
+  if (!is_a<greturn *> (s))
+    return;
+
+  // Check if the single return value is a symbolic and supported type.
+  greturn *gret = as_a<greturn *> (s);
+  tree op = gimple_return_retval (gret);
+  if (!gimple_range_ssa_p (op))
+    return;
+  tree lhs_type = TREE_TYPE (op);
+  if (!irange::supports_p (lhs_type))
+    return;
+
+  // Only values of interest are when the return value is 1.  The defintion
+  // of the return value must be in the same block, or we have
+  // complicated flow control we don't understand, and just return.
+  unsigned prec = TYPE_PRECISION (lhs_type);
+  int_range<2> lhs_range (lhs_type, wi::one (prec), wi::one (prec));
+
+  gimple *def = SSA_NAME_DEF_STMT (op);
+  if (!def || gimple_get_lhs (def) != op || gimple_bb (def) != bb)
+    return;
+
+  // Determine if this is a PHI or a linear sequence to deal with.
+  if (is_a<gphi *> (def))
+    calculate_phi (as_a<gphi *> (def), lhs_range);
+  else
+    process_stmts (def, lhs_range);
+
+  if (dump_file)
+    fprintf (dump_file, "Assumptions :\n--------------\n");
+
+  // Now export any interesting values that were found.
+  bitmap_iterator bi;
+  unsigned x;
+  EXECUTE_IF_SET_IN_BITMAP (m_parm_list, 0, x, bi)
+    {
+      tree name = ssa_name (x);
+      tree type = TREE_TYPE (name);
+      value_range assume_range (type);
+      // Set the global range of NAME to anything calculated.
+      if (m_parms.get_range (assume_range, name) && !assume_range.varying_p ())
+	set_range_info (name, assume_range);
+    }
+}
+
+// This function Will update all the current value of interesting parameters.
+// It tries, in order:
+//    a) a range found via path calculations.
+//    b) range of the parm at SRC point in the IL. (either edge or stmt)
+//    c) VARYING if those options fail.
+//  The value is then unioned with any existing value, allowing for the
+//  cumulation of all ranges leading to the return that return 1.
+
+void
+assume_query::update_parms (fur_source &src)
+{
+  // Merge any parameter values.
+  bitmap_iterator bi;
+  unsigned x;
+  EXECUTE_IF_SET_IN_BITMAP (m_parm_list, 0, x, bi)
+    {
+      tree name = ssa_name (x);
+      tree type = TREE_TYPE (name);
+
+      // Find a valu efrom calculations.
+      value_range glob_range (type);
+      if (!m_path.get_range (glob_range, name)
+	  && !src.get_operand (glob_range, name))
+	glob_range.set_varying (type);
+
+      // Find any current value of parm, and combine them.
+      value_range parm_range (type);
+      if (m_parms.get_range (parm_range, name))
+	glob_range.union_ (parm_range);
+
+      // Set this new value.
+      m_parms.set_range (name, glob_range);
+    }
+  // Now reset the path values for the next path.
+  m_path.clear ();
+}
+
+
+// Evaluate PHI statement, using the provided LHS range.
+// Only process edge that are both taken and returns the LHS of the PHI.
+
+void
+assume_query::calculate_phi (gphi *phi, vrange &lhs_range)
+{
+  for (unsigned x= 0; x < gimple_phi_num_args (phi); x++)
+    {
+      tree arg = gimple_phi_arg_def (phi, x);
+      value_range arg_range (TREE_TYPE (arg));
+      edge e = gimple_phi_arg_edge (phi, x);
+      value_range edge_range (TREE_TYPE (arg));
+      // If we can't get an edge range, be conservative and assume the
+      // edge can be taken.
+      // NOte this can be either an ssa_name or a constant.
+      if (get_range_query (m_func)->range_on_edge (edge_range, e, arg))
+	{
+	  if (gimple_range_ssa_p (arg))
+	    {
+	      arg_range = lhs_range;
+	      range_cast (arg_range, TREE_TYPE (arg));
+
+	      // An SSA_NAME arg will start with the LHS value.
+	      // Check the range of ARG on the edge leading here.  If that range
+	      // cannot be any value from the LHS of the PHI, then this branch
+	      // will not  be taken to return the LHS value and can be ignored.
+	      arg_range.intersect (edge_range);
+	      if (arg_range.undefined_p ())
+		continue;
+
+	      // If the def is in the immediate preceeding block, process it
+	      // with GORI to determine what values can produce this
+	      // argument value.  Otherwise there is more flow, so just query
+	      // the edge for parm ranges and be conservative.
+	      gimple *def_stmt = SSA_NAME_DEF_STMT (arg);
+	      if (def_stmt && gimple_get_lhs (def_stmt) == arg
+		  && gimple_bb (def_stmt) == e->src)
+		{
+		  process_stmts (def_stmt, arg_range);
+		  continue;
+		}
+	      // Fall through to process the edge.
+	    }
+	  else
+	    {
+	      // If this is a constant value that differs from LHS, this
+	      // edge cannot be taken and we can ignore it. Otherwise fall
+	      // thorugh and process the edge.
+	      edge_range.intersect (lhs_range);
+	      if (edge_range.undefined_p ())
+		continue;
+	    }
+	}
+      // If this point is reached the edge needs processing.
+      fur_edge src (e, get_range_query (m_func));
+      update_parms (src);
+    }
+}
+
+// Evaluate operand OP on statement S, using the provided LHS range.
+// If successful, set the range in path table, then visit OP's def stmt
+// if it is in the same BB.
+
+void
+assume_query::calculate_op (tree op, gimple *s, vrange &lhs, fur_source &src)
+{
+  basic_block bb = gimple_bb (s);
+  value_range op_range (TREE_TYPE (op));
+  if (src.gori () &&
+      src.gori ()->compute_operand_range (op_range, s, lhs, op, src)
+      && !op_range.varying_p ())
+    {
+      // Set the global range, merging if there is already a range.
+      m_path.merge_range (op, op_range);
+      gimple *def_stmt = SSA_NAME_DEF_STMT (op);
+      // Terminate if the patway leads to a different block as we
+      // are not analyzing flow.
+      if (def_stmt && gimple_get_lhs (def_stmt) == op
+	  && gimple_bb (def_stmt) == bb)
+	calculate_stmt (def_stmt, op_range, src);
+    }
+}
+
+
+// Evaluate statement S which produces range LHS_RANGE.  Use GORI to
+// determine what values the operands can have to produce the LHS,
+// and set these in the M_PATH table.
+
+void
+assume_query::calculate_stmt (gimple *s, vrange &lhs_range, fur_source &src)
+{
+  gimple_range_op_handler handler (s);
+  if (handler)
+    {
+      tree op = gimple_range_ssa_p (handler.operand1 ());
+      if (op)
+	calculate_op (op, s, lhs_range, src);
+      op = gimple_range_ssa_p (handler.operand2 ());
+      if (op)
+	calculate_op (op, s, lhs_range, src);
+    }
+}
+
+namespace {
+
+const pass_data pass_data_assumptions =
+{
+  GIMPLE_PASS, /* type */
+  "assumptions", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_ASSUMPTIONS, /* tv_id */
+  PROP_ssa, /* properties_required */
+  PROP_assumptions_done, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_end */
+};
+
+
+class pass_assumptions : public gimple_opt_pass
+{
+public:
+  pass_assumptions (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_assumptions, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate (function *fun) final override { return fun->assume_function; }
+  unsigned int execute (function *fun) final override
+    {
+      // Create a bitmap of all the paramters in this function.
+      // Invoke the assume_query to detemine what values these parameters
+      // have when the function returns TRUE, and set the globals value of
+      // those parameters in this function based on that.  This will later be
+      // utilized by ranger when prcessing the builtin_assumer function.
+      auto_bitmap decls;
+      for (tree arg = DECL_ARGUMENTS (fun->decl); arg; arg = DECL_CHAIN (arg))
+	{
+	  tree name = ssa_default_def (fun, arg);
+	  if (!name || !gimple_range_ssa_p (name))
+	    continue;
+	  tree type = TREE_TYPE (name);
+	  if (!value_range::supports_type_p (type))
+	    continue;
+	  bitmap_set_bit (decls, SSA_NAME_VERSION (name));
+	}
+      // If there are no parameters to map, simply return;
+      if (bitmap_empty_p (decls))
+	return TODO_discard_function;
+
+      enable_ranger (fun);
+
+      // This assume query will set any global values required.
+      assume_query query (fun, decls);
+
+      disable_ranger (fun);
+      return TODO_discard_function;
+    }
+
+}; // class pass_assumptions
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_assumptions (gcc::context *ctx)
+{
+  return new pass_assumptions (ctx);
+}
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index c265672bf99..f40bd6cdf5a 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -1353,60 +1353,6 @@  public:
   const pass_data &data;
   bool final_p;
 }; // class pass_vrp
-
-const pass_data pass_data_assumptions =
-{
-  GIMPLE_PASS, /* type */
-  "assumptions", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  TV_TREE_ASSUMPTIONS, /* tv_id */
-  PROP_ssa, /* properties_required */
-  PROP_assumptions_done, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  0, /* todo_flags_end */
-};
-
-class pass_assumptions : public gimple_opt_pass
-{
-public:
-  pass_assumptions (gcc::context *ctxt)
-    : gimple_opt_pass (pass_data_assumptions, ctxt)
-  {}
-
-  /* opt_pass methods: */
-  bool gate (function *fun) final override { return fun->assume_function; }
-  unsigned int execute (function *) final override
-    {
-      assume_query query;
-      if (dump_file)
-	fprintf (dump_file, "Assumptions :\n--------------\n");
-
-      for (tree arg = DECL_ARGUMENTS (cfun->decl); arg; arg = DECL_CHAIN (arg))
-	{
-	  tree name = ssa_default_def (cfun, arg);
-	  if (!name || !gimple_range_ssa_p (name))
-	    continue;
-	  tree type = TREE_TYPE (name);
-	  if (!value_range::supports_type_p (type))
-	    continue;
-	  value_range assume_range (type);
-	  // Set the global range of NAME to anything calculated.
-	  if (query.assume_range_p (assume_range, name))
-	    set_range_info (name, assume_range);
-	}
-      if (dump_file)
-	{
-	  fputc ('\n', dump_file);
-	  gimple_dump_cfg (dump_file, dump_flags & ~TDF_DETAILS);
-	  if (dump_flags & TDF_DETAILS)
-	    query.dump (dump_file);
-	}
-      return TODO_discard_function;
-    }
-
-}; // class pass_assumptions
-
 } // anon namespace
 
 gimple_opt_pass *
@@ -1426,9 +1372,3 @@  make_pass_fast_vrp (gcc::context *ctxt)
 {
   return new pass_vrp (ctxt, pass_data_fast_vrp);
 }
-
-gimple_opt_pass *
-make_pass_assumptions (gcc::context *ctx)
-{
-  return new pass_assumptions (ctx);
-}
-- 
2.45.0