From 4b955ac10f3d978a9be491d9c5277778da005895 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Wed, 13 Mar 2024 14:18:48 -0400
Subject: [PATCH 4/9] Add range_on_entry/exit to value_query API.

Add range_on_entry and range_on_exit to the value_query API.  These will
also work with generic trees like range_of_expr does.

	* gimple-range.cc (gimple_ranger::range_on_entry): Adjust for new
	API and support non-SSA expressions.
	(gimple_ranger::range_on_exit): Ditto.
	* gimple-range.h (range_on_entry, range_on_exit): Adjust API.
	* value-query.cc (range_query::range_on_entry): New.
	(range_query::range_on_exit): New.
	(range_query::value_on_entry): New.
	(range_query::value_on_exit): New.
	(range_query::invoke_range_of_expr): New.
	(range_query::get_tree_range): Allow stmt, on_entry or on_exit
	range queries.
	SSA_NAMES should invoke range_of_expr if possible.
	* value-query.h (class range_query): Adjust prototypes.
---
 gcc/gimple-range.cc |  14 ++++---
 gcc/gimple-range.h  |   4 +-
 gcc/value-query.cc  | 100 ++++++++++++++++++++++++++++++++++++++++----
 gcc/value-query.h   |   9 +++-
 4 files changed, 112 insertions(+), 15 deletions(-)

diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 3966cfbd14c..e75e2e17dc3 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -152,11 +152,13 @@ gimple_ranger::range_of_expr (vrange &r, tree expr, gimple *stmt)
 
 // Return the range of NAME on entry to block BB in R.
 
-void
+bool
 gimple_ranger::range_on_entry (vrange &r, basic_block bb, tree name)
 {
+  if (!gimple_range_ssa_p (name))
+    return get_tree_range (r, name, NULL, bb, NULL);
+
   Value_Range entry_range (TREE_TYPE (name));
-  gcc_checking_assert (gimple_range_ssa_p (name));
 
   unsigned idx;
   if ((idx = tracer.header ("range_on_entry (")))
@@ -174,16 +176,17 @@ gimple_ranger::range_on_entry (vrange &r, basic_block bb, tree name)
 
   if (idx)
     tracer.trailer (idx, "range_on_entry", true, name, r);
+  return true;
 }
 
 // Calculate the range for NAME at the end of block BB and return it in R.
 // Return false if no range can be calculated.
 
-void
+bool
 gimple_ranger::range_on_exit (vrange &r, basic_block bb, tree name)
 {
-  // on-exit from the exit block?
-  gcc_checking_assert (gimple_range_ssa_p (name));
+  if (!gimple_range_ssa_p (name))
+    return get_tree_range (r, name, NULL, NULL, bb);
 
   unsigned idx;
   if ((idx = tracer.header ("range_on_exit (")))
@@ -208,6 +211,7 @@ gimple_ranger::range_on_exit (vrange &r, basic_block bb, tree name)
   
   if (idx)
     tracer.trailer (idx, "range_on_exit", true, name, r);
+  return true;
 }
 
 // Calculate a range for NAME on edge E and return it in R.
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index 8739ab6a2ef..167b54b2a37 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -52,8 +52,8 @@ public:
   virtual bool range_of_stmt (vrange &r, gimple *, tree name = NULL) override;
   virtual bool range_of_expr (vrange &r, tree name, gimple * = NULL) override;
   virtual bool range_on_edge (vrange &r, edge e, tree name) override;
-  void range_on_entry (vrange &r, basic_block bb, tree name);
-  void range_on_exit (vrange &r, basic_block bb, tree name);
+  virtual bool range_on_entry (vrange &r, basic_block bb, tree name) override;
+  virtual bool range_on_exit (vrange &r, basic_block bb, tree name) override;
   void export_global_ranges ();
   inline gori_compute &gori ()  { return m_cache.m_gori; }
   virtual void dump (FILE *f) override;
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index e88c8e25789..c2ab745a466 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -41,6 +41,18 @@ range_query::range_on_edge (vrange &r, edge, tree expr)
   return range_of_expr (r, expr);
 }
 
+bool
+range_query::range_on_entry (vrange &r, basic_block, tree expr)
+{
+  return range_of_expr (r, expr);
+}
+
+bool
+range_query::range_on_exit (vrange &r, basic_block, tree expr)
+{
+  return range_of_expr (r, expr);
+}
+
 bool
 range_query::range_of_stmt (vrange &r, gimple *stmt, tree name)
 {
@@ -54,6 +66,9 @@ range_query::range_of_stmt (vrange &r, gimple *stmt, tree name)
   return false;
 }
 
+// If the range of expr EXPR at STMT is a single value, return it.
+// Otherwise return NULL_TREE.
+
 tree
 range_query::value_of_expr (tree expr, gimple *stmt)
 {
@@ -76,6 +91,9 @@ range_query::value_of_expr (tree expr, gimple *stmt)
   return NULL_TREE;
 }
 
+// If the range on edge E for EXPR is a single value, return it.
+// Otherwise return NULL_TREE.
+
 tree
 range_query::value_on_edge (edge e, tree expr)
 {
@@ -94,9 +112,11 @@ range_query::value_on_edge (edge e, tree expr)
 	return t;
     }
   return NULL_TREE;
-
 }
 
+// If the range of STMT for NAME is a single value, return it.
+// Otherwise return NULL_TREE.
+
 tree
 range_query::value_of_stmt (gimple *stmt, tree name)
 {
@@ -113,7 +133,44 @@ range_query::value_of_stmt (gimple *stmt, tree name)
   if (range_of_stmt (r, stmt, name) && r.singleton_p (&t))
     return t;
   return NULL_TREE;
+}
+
+// If the range on entry to BB for EXPR is a single value, return it.
+// Otherwise return NULL_TREE.
+
+tree
+range_query::value_on_entry (basic_block bb, tree expr)
+{
+  tree t;
 
+  gcc_checking_assert (bb);
+  if (!Value_Range::supports_type_p (TREE_TYPE (expr)))
+    return NULL_TREE;
+
+  Value_Range r (TREE_TYPE (expr));
+
+  if (range_on_entry (r, bb, expr) && r.singleton_p (&t))
+    return t;
+  return NULL_TREE;
+}
+
+// If the range on exit to BB for EXPR is a single value, return it.
+// Otherwise return NULL_TREE.
+
+tree
+range_query::value_on_exit (basic_block bb, tree expr)
+{
+  tree t;
+
+  gcc_checking_assert (bb);
+  if (!Value_Range::supports_type_p (TREE_TYPE (expr)))
+    return NULL_TREE;
+
+  Value_Range r (TREE_TYPE (expr));
+
+  if (range_on_exit (r, bb, expr) && r.singleton_p (&t))
+    return t;
+  return NULL_TREE;
 }
 
 void
@@ -130,11 +187,36 @@ range_query::~range_query ()
 {
 }
 
-// Return a range in R for the tree EXPR.  Return true if a range is
-// representable, and UNDEFINED/false if not.
+// This routine will invoke the equivalent of range_of_expr on
+// either a gimple statement STMT, on entry to block BBENTRY, or on
+// exit from block BBEXIT.   Only one of these 3 fields may be set.
+// It is valid for none of them to be set, in wqhich case there is no context.
+
+bool
+range_query::invoke_range_of_expr (vrange &r, tree expr, gimple *stmt,
+				   basic_block bbentry, basic_block bbexit)
+{
+  if (bbentry)
+    {
+      gcc_checking_assert (!stmt && !bbexit);
+      return range_on_entry (r, bbentry, expr);
+    }
+  if (bbexit)
+    {
+      gcc_checking_assert (!stmt);
+      return range_on_exit (r, bbexit, expr);
+    }
+
+  return range_of_expr (r, expr, stmt);
+}
+
+// Return a range in R for the tree EXPR.  The context can be either a STMT,
+// or on entry to block BBENTRY or exit from block BBEXIT.
+// Return true if a range is representable, and UNDEFINED/false if not.
 
 bool
-range_query::get_tree_range (vrange &r, tree expr, gimple *stmt)
+range_query::get_tree_range (vrange &r, tree expr, gimple *stmt,
+			     basic_block bbentry, basic_block bbexit)
 {
   tree type;
   if (TYPE_P (expr))
@@ -180,6 +262,9 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt)
       }
 
     case SSA_NAME:
+      // If this is not an abnormal or virtual ssa, invoke range_of_expr.
+      if (gimple_range_ssa_p (expr))
+	return invoke_range_of_expr (r, expr, stmt, bbentry, bbexit);
       gimple_range_global (r, expr);
       return true;
 
@@ -210,8 +295,8 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt)
 	{
 	  Value_Range r0 (TREE_TYPE (op0));
 	  Value_Range r1 (TREE_TYPE (op1));
-	  range_of_expr (r0, op0, stmt);
-	  range_of_expr (r1, op1, stmt);
+	  invoke_range_of_expr (r0, op0, stmt, bbentry, bbexit);
+	  invoke_range_of_expr (r1, op1, stmt, bbentry, bbexit);
 	  if (!op.fold_range (r, type, r0, r1))
 	    r.set_varying (type);
 	}
@@ -228,7 +313,8 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt)
 	  Value_Range r0 (TREE_TYPE (TREE_OPERAND (expr, 0)));
 	  Value_Range r1 (type);
 	  r1.set_varying (type);
-	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
+	  invoke_range_of_expr (r0, TREE_OPERAND (expr, 0), stmt, bbentry,
+				bbexit);
 	  if (!op.fold_range (r, type, r0, r1))
 	    r.set_varying (type);
 	}
diff --git a/gcc/value-query.h b/gcc/value-query.h
index a1306e2bd25..4d2a7bce485 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -60,6 +60,8 @@ public:
   virtual tree value_of_expr (tree expr, gimple * = NULL);
   virtual tree value_on_edge (edge, tree expr);
   virtual tree value_of_stmt (gimple *, tree name = NULL);
+  virtual tree value_on_entry (basic_block, tree expr);
+  virtual tree value_on_exit (basic_block, tree expr);
 
   // These are the range equivalents of the value_* methods.  Instead
   // of returning a singleton, they calculate a range and return it in
@@ -70,6 +72,8 @@ public:
   virtual bool range_of_expr (vrange &r, tree expr, gimple * = NULL) = 0;
   virtual bool range_on_edge (vrange &r, edge, tree expr);
   virtual bool range_of_stmt (vrange &r, gimple *, tree name = NULL);
+  virtual bool range_on_entry (vrange &r, basic_block bb, tree expr);
+  virtual bool range_on_exit (vrange &r, basic_block bb, tree expr);
 
   // Query if there is any relation between SSA1 and SSA2.
   relation_kind query_relation (gimple *s, tree ssa1, tree ssa2,
@@ -82,7 +86,10 @@ public:
   virtual void dump (FILE *);
 
 protected:
-  bool get_tree_range (vrange &v, tree expr, gimple *stmt);
+  bool get_tree_range (vrange &v, tree expr, gimple *stmt,
+		       basic_block bbentry = NULL, basic_block bbexit = NULL);
+  bool invoke_range_of_expr (vrange &v, tree expr, gimple *stmt,
+			     basic_block bbentry, basic_block bbexit);
   bool get_arith_expr_range (vrange &r, tree expr, gimple *stmt);
   relation_oracle *m_oracle;
 };
-- 
2.41.0

