From 837ce8a2d75231b68f13da00d9be8d2fd404804e Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Fri, 17 May 2024 10:50:24 -0400
Subject: [PATCH 05/12] Move infer_manager to a range_query oracle.

Turn the infer_manager class into an always available oracle accessible via a
range_query object.  Also assocaite each inferrred range with it's
originating stmt.

	* gimple-range-cache.cc (ranger_cache::ranger_cache): Create an infer
	oracle instead of a local member.
	(ranger_cache::~ranger_cache): Destroy the oracle.
	(ranger_cache::edge_range): Use oracle.
	(ranger_cache::fill_block_cache): Likewise.
	(ranger_cache::range_from_dom): Likewise.
	(ranger_cache::apply_inferred_ranges): Likewise.
	* gimple-range-cache.h (ranger_cache::m_exit): Delete.
	* gimple-range-infer.cc (infer_oracle): New static object;
	(class infer_oracle): New.
	(non_null_wrapper::non_null_wrapper): New.
	(non_null_wrapper::add_nonzero): New.
	(non_null_wrapper::add_range): New.
	(non_null_loadstore): Use nonnull_wrapper.
	(gimple_infer_range::gimple_infer_range): New alternate constructor.
	(exit_range::stmt): New.
	(infer_range_manager::has_range_p): Combine seperate methods.
	(infer_range_manager::maybe_adjust_range): Adjust has_range_p call.
	(infer_range_manager::add_ranges): New.
	(infer_range_manager::add_range): Take stmt rather than BB.
	(infer_range_manager::add_nonzero): Adjust from BB to stmt.
	* gimple-range-infer.h (class gimple_infer_range): Adjust methods.
	(infer_range_oracle): New.
	(class infer_range_manager): Inherit from infer_range_oracle.
	Adjust methods.
	* gimple-range-path.cc (path_range_query::range_defined_in_block): Use
	oracle.
	(path_range_query::adjust_for_non_null_uses): Likewise.
	* gimple-range.cc (gimple_ranger::range_on_edge): Likewise
	(gimple_ranger::register_transitive_inferred_ranges): Likewise.
	* value-query.cc (default_infer_oracle): New.
	(range_query::create_infer_oracle): New.
	(range_query::destroy_infer_oracle): New.
	(range_query::share_query): Copy infer pointer.
	(range_query::range_query): Initialize infer pointer.
	(range_query::~range_query): destroy infer object.
	* value-query.h (range_query::infer_oracle): New.
	(range_query::create_infer_oracle): New prototype.
	(range_query::destroy_infer_oracle): New prototype.
	(range_query::m_infer): New.
---
 gcc/gimple-range-cache.cc | 24 +++++------
 gcc/gimple-range-cache.h  |  1 -
 gcc/gimple-range-infer.cc | 90 +++++++++++++++++++++++++++------------
 gcc/gimple-range-infer.h  | 31 ++++++++++----
 gcc/gimple-range-path.cc  |  4 +-
 gcc/gimple-range.cc       | 14 +++---
 gcc/value-query.cc        | 20 +++++++++
 gcc/value-query.h         |  5 +++
 8 files changed, 131 insertions(+), 58 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 55277ea8af1..34dc9c4a3ec 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -950,8 +950,7 @@ update_list::pop ()
 // --------------------------------------------------------------------------
 
 ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
-						: m_gori (not_executable_flag),
-						  m_exit (use_imm_uses)
+						: m_gori (not_executable_flag)
 {
   m_workback.create (0);
   m_workback.safe_grow_cleared (last_basic_block_for_fn (cfun));
@@ -960,6 +959,7 @@ ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
 
   // If DOM info is available, spawn an oracle as well.
   create_relation_oracle ();
+  create_infer_oracle (use_imm_uses);
 
   unsigned x, lim = last_basic_block_for_fn (cfun);
   // Calculate outgoing range info upfront.  This will fully populate the
@@ -977,6 +977,7 @@ ranger_cache::ranger_cache (int not_executable_flag, bool use_imm_uses)
 ranger_cache::~ranger_cache ()
 {
   delete m_update;
+  destroy_infer_oracle ();
   destroy_relation_oracle ();
   delete m_temporal;
   m_workback.release ();
@@ -1175,7 +1176,7 @@ ranger_cache::edge_range (vrange &r, edge e, tree name, enum rfd_mode mode)
   exit_range (r, name, e->src, mode);
   // If this is not an abnormal edge, check for inferred ranges on exit.
   if ((e->flags & (EDGE_EH | EDGE_ABNORMAL)) == 0)
-    m_exit.maybe_adjust_range (r, name, e->src);
+    infer_oracle ().maybe_adjust_range (r, name, e->src);
   Value_Range er (TREE_TYPE (name));
   if (m_gori.outgoing_edge_range_p (er, e, name, *this))
     r.intersect (er);
@@ -1544,7 +1545,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
 	  // Regardless of whether we have visited pred or not, if the
 	  // pred has inferred ranges, revisit this block.
 	  // Don't search the DOM tree.
-	  if (m_exit.has_range_p (name, pred))
+	  if (infer_oracle ().has_range_p (pred, name))
 	    {
 	      if (DEBUG_RANGE_CACHE)
 		fprintf (dump_file, "Inferred range: update ");
@@ -1667,7 +1668,7 @@ ranger_cache::range_from_dom (vrange &r, tree name, basic_block start_bb,
   for ( ; bb; prev_bb = bb, bb = get_immediate_dominator (CDI_DOMINATORS, bb))
     {
       // Accumulate any block exit inferred ranges.
-      m_exit.maybe_adjust_range (infer, name, bb);
+      infer_oracle ().maybe_adjust_range (infer, name, bb);
 
       // This block has an outgoing range.
       if (m_gori.has_edge_range_p (name, bb))
@@ -1742,7 +1743,7 @@ ranger_cache::range_from_dom (vrange &r, tree name, basic_block start_bb,
 	  r.intersect (er);
 	  // If this is a normal edge, apply any inferred ranges.
 	  if ((e->flags & (EDGE_EH | EDGE_ABNORMAL)) == 0)
-	    m_exit.maybe_adjust_range (r, name, bb);
+	    infer_oracle ().maybe_adjust_range (r, name, bb);
 
 	  if (DEBUG_RANGE_CACHE)
 	    {
@@ -1811,11 +1812,8 @@ ranger_cache::apply_inferred_ranges (gimple *s)
 	update = false;
     }
 
-  for (unsigned x = 0; x < infer.num (); x++)
-    {
-      tree name = infer.name (x);
-      m_exit.add_range (name, bb, infer.range (x));
-      if (update)
-	register_inferred_value (infer.range (x), name, bb);
-    }
+  infer_oracle ().add_ranges (s, infer);
+  if (update)
+    for (unsigned x = 0; x < infer.num (); x++)
+      register_inferred_value (infer.range (x), infer.name (x), bb);
 }
diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h
index bdf07cd007c..e3ab89de02e 100644
--- a/gcc/gimple-range-cache.h
+++ b/gcc/gimple-range-cache.h
@@ -115,7 +115,6 @@ public:
   void register_inferred_value (const vrange &r, tree name, basic_block bb);
   void apply_inferred_ranges (gimple *s);
   gori_compute m_gori;
-  infer_range_manager m_exit;
 
   void dump_bb (FILE *f, basic_block bb);
   virtual void dump (FILE *f) override;
diff --git a/gcc/gimple-range-infer.cc b/gcc/gimple-range-infer.cc
index d5e1aa14275..757a2013c58 100644
--- a/gcc/gimple-range-infer.cc
+++ b/gcc/gimple-range-infer.cc
@@ -37,6 +37,25 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfganal.h"
 #include "tree-dfa.h"
 
+// Create the global oracle.
+
+infer_range_oracle infer_oracle;
+
+// This class is merely an accessor which is granted internals to
+// gimple_infer_range such that non_null_loadstore as a static callback can
+// call the protected add_nonzero ().
+// Static functions ccannot be friends, so we do it through a class wrapper.
+
+class non_null_wrapper
+{
+public:
+  inline non_null_wrapper (gimple_infer_range *infer) : m_infer (infer) { }
+  inline void add_nonzero (tree name) { m_infer->add_nonzero (name); }
+  inline void add_range (tree t, vrange &r) { m_infer->add_range (t, r); }
+private:
+  gimple_infer_range *m_infer;
+};
+
 // Adapted from infer_nonnull_range_by_dereference and check_loadstore
 // to process nonnull ssa_name OP in S.  DATA contains a pointer to a
 // stmt range inference instance.
@@ -50,8 +69,8 @@ non_null_loadstore (gimple *, tree op, tree, void *data)
       addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (op));
       if (!targetm.addr_space.zero_address_valid (as))
 	{
-	  tree ssa = TREE_OPERAND (op, 0);
-	  ((gimple_infer_range *)data)->add_nonzero (ssa);
+	  non_null_wrapper wrapper ((gimple_infer_range *)data);
+	  wrapper.add_nonzero (TREE_OPERAND (op, 0));
 	}
     }
   return false;
@@ -173,6 +192,14 @@ gimple_infer_range::gimple_infer_range (gimple *s)
 
 }
 
+// Create an single inferred range for NAMe using range R.
+
+gimple_infer_range::gimple_infer_range (tree name, vrange &r)
+{
+  num_args = 0;
+  add_range (name, r);
+}
+
 // -------------------------------------------------------------------------
 
 // This class is an element in the list of inferred ranges.
@@ -181,10 +208,12 @@ class exit_range
 {
 public:
   tree name;
+  gimple *stmt;
   vrange_storage *range;
   exit_range *next;
 };
 
+
 // If there is an element which matches SSA, return a pointer to the element.
 // Otherwise return NULL.
 
@@ -253,33 +282,26 @@ infer_range_manager::get_nonzero (tree name)
   return *(m_nonzero[v]);
 }
 
-// Return TRUE if there are any range inferences in block BB.
-
-bool
-infer_range_manager::has_range_p (basic_block bb)
-{
-  if (bb->index >= (int)m_on_exit.length ())
-    return false;
-  bitmap b = m_on_exit[bb->index].m_names;
-  return b && !bitmap_empty_p (b);
-}
-
-// Return TRUE if NAME has a range inference in block BB.
+// Return TRUE if NAME has a range inference in block BB.  If NAME is NULL,
+// return TRUE if there are any name sin BB.
 
 bool
-infer_range_manager::has_range_p (tree name, basic_block bb)
+infer_range_manager::has_range_p (basic_block bb, tree name)
 {
   // Check if this is an immediate use search model.
-  if (m_seen && !bitmap_bit_p (m_seen, SSA_NAME_VERSION (name)))
+  if (name && m_seen && !bitmap_bit_p (m_seen, SSA_NAME_VERSION (name)))
     register_all_uses (name);
 
   if (bb->index >= (int)m_on_exit.length ())
     return false;
-  if (!m_on_exit[bb->index].m_names)
-    return false;
-  if (!bitmap_bit_p (m_on_exit[bb->index].m_names, SSA_NAME_VERSION (name)))
+
+  bitmap b = m_on_exit[bb->index].m_names;
+  if (!b)
     return false;
-  return true;
+
+  if (name)
+    return bitmap_bit_p (m_on_exit[bb->index].m_names, SSA_NAME_VERSION (name));
+  return !bitmap_empty_p (b);
 }
 
 // Return TRUE if NAME has a range inference in block BB, and adjust range R
@@ -288,7 +310,7 @@ infer_range_manager::has_range_p (tree name, basic_block bb)
 bool
 infer_range_manager::maybe_adjust_range (vrange &r, tree name, basic_block bb)
 {
-  if (!has_range_p (name, bb))
+  if (!has_range_p (bb, name))
     return false;
   exit_range *ptr = m_on_exit[bb->index].find_ptr (name);
   gcc_checking_assert (ptr);
@@ -299,11 +321,23 @@ infer_range_manager::maybe_adjust_range (vrange &r, tree name, basic_block bb)
   return r.intersect (tmp);
 }
 
-// Add range R as an inferred range for NAME in block BB.
+// Add all inferred ranges in INFER at stmt S.
+
+void
+infer_range_manager::add_ranges (gimple *s, gimple_infer_range &infer)
+{
+  for (unsigned x = 0; x < infer.num (); x++)
+    add_range (infer.name (x), s, infer.range (x));
+}
+
+// Add range R as an inferred range for NAME on stmt S.
 
 void
-infer_range_manager::add_range (tree name, basic_block bb, const vrange &r)
+infer_range_manager::add_range (tree name, gimple *s, const vrange &r)
 {
+  basic_block bb = gimple_bb (s);
+  if (!bb)
+    return;
   if (bb->index >= (int)m_on_exit.length ())
     m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
 
@@ -334,6 +368,7 @@ infer_range_manager::add_range (tree name, basic_block bb, const vrange &r)
 	ptr->range->set_vrange (cur);
       else
 	ptr->range = m_range_allocator->clone (cur);
+      ptr->stmt = s;
       return;
     }
 
@@ -342,16 +377,17 @@ infer_range_manager::add_range (tree name, basic_block bb, const vrange &r)
   ptr = (exit_range *)obstack_alloc (&m_list_obstack, sizeof (exit_range));
   ptr->range = m_range_allocator->clone (r);
   ptr->name = name;
+  ptr->stmt = s;
   ptr->next = m_on_exit[bb->index].head;
   m_on_exit[bb->index].head = ptr;
 }
 
-// Add a non-zero inferred range for NAME in block BB.
+// Add a non-zero inferred range for NAME at stmt S.
 
 void
-infer_range_manager::add_nonzero (tree name, basic_block bb)
+infer_range_manager::add_nonzero (tree name, gimple *s)
 {
-  add_range (name, bb, get_nonzero (name));
+  add_range (name, s, get_nonzero (name));
 }
 
 // Follow immediate use chains and find all inferred ranges for NAME.
@@ -378,7 +414,7 @@ infer_range_manager::register_all_uses (tree name)
       for (unsigned x = 0; x < infer.num (); x++)
 	{
 	  if (name == infer.name (x))
-	    add_range (name, gimple_bb (s), infer.range (x));
+	    add_range (name, s, infer.range (x));
 	}
     }
 }
diff --git a/gcc/gimple-range-infer.h b/gcc/gimple-range-infer.h
index 384d8b2765e..fd5b2ad8dde 100644
--- a/gcc/gimple-range-infer.h
+++ b/gcc/gimple-range-infer.h
@@ -32,20 +32,35 @@ class gimple_infer_range
 {
 public:
   gimple_infer_range (gimple *s);
+  gimple_infer_range (tree name, vrange &r);
   inline unsigned num () const { return num_args; }
   inline tree name (unsigned index) const
     { gcc_checking_assert (index < num_args); return m_names[index]; }
   inline const vrange& range (unsigned index) const
     { gcc_checking_assert (index < num_args); return m_ranges[index]; }
+private:
   void add_range (tree name, vrange &range);
   void add_nonzero (tree name);
-private:
   void check_assume_func (gcall *call);
   unsigned num_args;
   static const int size_limit = 10;
   tree m_names[size_limit];
   Value_Range m_ranges[size_limit];
   inline void bump_index () { if (num_args < size_limit - 1) num_args++; }
+  friend class non_null_wrapper;
+};
+
+// This is the basic infer oracle API.  Default functionaility does nothing.
+
+class infer_range_oracle
+{
+public:
+  infer_range_oracle () { }
+  virtual ~infer_range_oracle () { }
+  virtual void add_ranges (gimple *, gimple_infer_range &) { }
+  virtual bool has_range_p (basic_block, tree = NULL_TREE) { return false; }
+  virtual bool maybe_adjust_range (vrange &, tree, basic_block)
+      { return false; }
 };
 
 // This class manages a list of inferred ranges for each basic block.
@@ -54,17 +69,17 @@ private:
 // followed the first time a name is referenced and block populated if
 // there are any inferred ranges.
 
-class infer_range_manager
+class infer_range_manager : public infer_range_oracle
 {
 public:
   infer_range_manager (bool do_search);
-  ~infer_range_manager ();
-  void add_range (tree name, basic_block bb, const vrange &r);
-  void add_nonzero (tree name, basic_block bb);
-  bool has_range_p (tree name, basic_block bb);
-  bool has_range_p (basic_block bb);
-  bool maybe_adjust_range (vrange &r, tree name, basic_block bb);
+  virtual ~infer_range_manager ();
+  virtual void add_ranges (gimple *s, gimple_infer_range &ir);
+  virtual bool has_range_p (basic_block bb, tree name = NULL_TREE);
+  virtual bool maybe_adjust_range (vrange &r, tree name, basic_block bb);
 private:
+  void add_range (tree name, gimple *s, const vrange &r);
+  void add_nonzero (tree name, gimple *s);
   class exit_range_head
   {
   public:
diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc
index e35bec0e50d..b35ab43524b 100644
--- a/gcc/gimple-range-path.cc
+++ b/gcc/gimple-range-path.cc
@@ -303,7 +303,7 @@ path_range_query::range_defined_in_block (vrange &r, tree name, basic_block bb)
     }
 
   if (bb && POINTER_TYPE_P (TREE_TYPE (name)))
-    m_ranger.m_cache.m_exit.maybe_adjust_range (r, name, bb);
+    m_ranger.infer_oracle ().maybe_adjust_range (r, name, bb);
 
   if (DEBUG_SOLVER && (bb || !r.varying_p ()))
     {
@@ -463,7 +463,7 @@ path_range_query::adjust_for_non_null_uses (basic_block bb)
       else
 	r.set_varying (TREE_TYPE (name));
 
-      if (m_ranger.m_cache.m_exit.maybe_adjust_range (r, name, bb))
+      if (m_ranger.infer_oracle ().maybe_adjust_range (r, name, bb))
 	m_cache.set_range (name, r);
     }
 }
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 4326976fc2a..efc84dc3b44 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -253,7 +253,7 @@ gimple_ranger::range_on_edge (vrange &r, edge e, tree name)
       range_on_exit (r, e->src, name);
       // If this is not an abnormal edge, check for a non-null exit .
       if ((e->flags & (EDGE_EH | EDGE_ABNORMAL)) == 0)
-	m_cache.m_exit.maybe_adjust_range (r, name, e->src);
+	infer_oracle ().maybe_adjust_range (r, name, e->src);
       gcc_checking_assert  (r.undefined_p ()
 			    || range_compatible_p (r.type(), TREE_TYPE (name)));
 
@@ -516,8 +516,7 @@ void
 gimple_ranger::register_transitive_inferred_ranges (basic_block bb)
 {
   // Return if there are no inferred ranges in BB.
-  infer_range_manager &infer = m_cache.m_exit;
-  if (!infer.has_range_p (bb))
+  if (!infer_oracle ().has_range_p (bb))
     return;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -530,7 +529,7 @@ gimple_ranger::register_transitive_inferred_ranges (basic_block bb)
       gimple *s = gsi_stmt (si);
       tree lhs = gimple_get_lhs (s);
       // If the LHS already has an inferred effect, leave it be.
-      if (!gimple_range_ssa_p (lhs) || infer.has_range_p (lhs, bb))
+      if (!gimple_range_ssa_p (lhs) || infer_oracle ().has_range_p (bb, lhs))
 	continue;
       // Pick up global value.
       Value_Range g (TREE_TYPE (lhs));
@@ -543,13 +542,14 @@ gimple_ranger::register_transitive_inferred_ranges (basic_block bb)
       r.set_undefined ();
       tree name1 = gori ().depend1 (lhs);
       tree name2 = gori ().depend2 (lhs);
-      if ((name1 && infer.has_range_p (name1, bb))
-	  || (name2 && infer.has_range_p (name2, bb)))
+      if ((name1 && infer_oracle ().has_range_p (bb, name1))
+	  || (name2 && infer_oracle ().has_range_p (bb, name2)))
 	{
 	  // Check if folding S produces a different result.
 	  if (fold_range (r, s, this) && g != r)
 	    {
-	      infer.add_range (lhs, bb, r);
+	      gimple_infer_range ir (lhs, r);
+	      infer_oracle ().add_ranges (s, ir);
 	      m_cache.register_inferred_value (r, lhs, bb);
 	    }
 	}
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index adcc59cadbf..41b581b20be 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -181,6 +181,23 @@ range_query::dump (FILE *)
 // Default oracle for all range queries.  This contains no storage and thus
 // can be used anywhere.
 relation_oracle default_relation_oracle;
+infer_range_oracle default_infer_oracle;
+
+void
+range_query::create_infer_oracle (bool do_search)
+{
+  gcc_checking_assert (m_infer == &default_infer_oracle);
+  m_infer = new infer_range_manager (do_search);
+  gcc_checking_assert (m_infer);
+}
+
+void
+range_query::destroy_infer_oracle ()
+{
+  if (m_infer && m_infer != &default_infer_oracle)
+    delete m_infer;
+  m_infer = &default_infer_oracle;
+}
 
 // Create dominance based range oracle for the current query if dom info is
 // available.
@@ -215,12 +232,14 @@ void
 range_query::share_query (range_query &q)
 {
   m_relation = q.m_relation;
+  m_infer = q.m_infer;
   m_shared_copy_p = true;
 }
 
 range_query::range_query ()
 {
   m_relation = &default_relation_oracle;
+  m_infer = &default_infer_oracle;
   m_shared_copy_p = false;
 }
 
@@ -229,6 +248,7 @@ range_query::~range_query ()
   // Do not destroy anything if this is a shared copy.
   if (m_shared_copy_p)
     return;
+  destroy_infer_oracle ();
   destroy_relation_oracle ();
 }
 
diff --git a/gcc/value-query.h b/gcc/value-query.h
index a5735902af0..2f65d95bc9b 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -79,6 +79,10 @@ public:
   void create_relation_oracle ();
   void destroy_relation_oracle ();
 
+  inline class infer_range_oracle &infer_oracle () const { return *m_infer; }
+  void create_infer_oracle (bool do_search = TRUE);
+  void destroy_infer_oracle ();
+
   virtual void dump (FILE *);
 
 protected:
@@ -88,6 +92,7 @@ protected:
 			     basic_block bbentry, basic_block bbexit);
   bool get_arith_expr_range (vrange &r, tree expr, gimple *stmt);
   relation_oracle *m_relation;
+  infer_range_oracle *m_infer;
   // When multiple related range queries wish to share oracles.
   // This is an internal interface
   void share_query (range_query &q);
-- 
2.41.0

