[COMMITTED] PR tree-optimization/126856 - Provide a range_info reset method.

Andrew MacLeod <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
My patch for 126329 allows early removal of builtin_unreachable to 
proceed by replacing dead statements with an assignment to zero instead 
of removing them.

In theory that was safe because there were no uses of the name in the 
IL.   The fallout was that if there was an existing equivalence or 
relation with some other ssa name, this  made those equivalences and 
relations now relative to [0, 0].  oops.

I looked at a few options, and they all seemed a bit hacky.. In the end, 
Ive provided a way to remove all relevant information about a range from 
all the various components... Ranger, the relation oracle, the inferred 
range oracle, and gori.   Although this might seem like a bit of 
overkill, it fills a gap that was uncovered a few months ago with 
reset_flow_sensitive_info.

There are uses of reset_flow_sensitive_info (name) sprinkled around the 
compiler which currently kills just  the SSA_NAME_RANGE_INFO for an SSA 
NAME.  It won't affect ranger or any other component, and this may lead 
to behaviour the developer is not expecting.

With this patch, a range_query object now has a reset_range_info () 
which is called by reset_flow_sensitive_info () and corrects this 
situation.  It will clear any range info from the current range object, 
as well as the various oracles.. relations, inferred ranges, and gori.   
Its a bit heavy handed but does a full job.  I had considered just 
clearing some of the cache flags, but if the ssa_name were to be used 
again (and other use cases may expect that) some of the old relations 
would have popped back into existence.   This now expunges all of them.  
Overall compile time building gcc is actually a wash.

The DCE fix for this PR now simply calls reset_flow_sensitive_info on 
the ssa-name when it rewrites the statement to be an assignment of 0.  
This clears all the information that may cause issues, and life is 
hopefully good again.

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

Andrew
0001-Provide-a-range_info-reset-method.patch (text/x-patch, 15.5 KB)
From 06f435d587db631be745eb36c46e550939022827 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <[email protected]>
Date: Tue, 18 Aug 2026 08:58:35 -0400
Subject: [PATCH] Provide a range_info reset method.

Provide a mechanism to reset range info in ranger and the oracles.

	PR tree-optimization/126856
	gcc/
	* gimple-range-cache.cc (block_range_cache::clear): New.
	(ranger_cache::reset_range_info): New.
	* gimple-range-cache.h (block_range_cache::clear): Declare.
	(ranger_cache::reset_range_info): Declare.
	* gimple-range-gori.cc (range_def_chain::clear): New.
	* gimple-range-gori.h (range_def_chain::clear): Declare.
	* gimple-range-infer.cc (infer_range_manager::clear): New.
	* gimple-range-infer.h (infer_oracle::clear): New virtual function.
	(infer_range_manager::clear): Override.
	* gimple-range.cc (gimple_ranger::reset_range_info): New.
	* gimple-range.h (gimple_ranger::reset_range_info): Declare.
	* tree-ssa-dce.cc (simple_dce_from_worklist): Reset flow-sensitive
	information when replacing a definition.
	* tree-ssanames.cc (reset_flow_sensitive_info): Reset information
	maintained by the current range query.
	* value-query.cc (range_query::reset_range_info): New.
	* value-query.h (range_query::reset_range_info): Declare.
	* value-relation.cc (equiv_oracle::clear): New.
	(relation_chain_head::clear): New.
	(dom_oracle::clear): New.
	(path_oracle::clear): New.
	* value-relation.h (relation_oracle::clear): New virtual function.
	(equiv_oracle::clear): Override.
	(relation_chain_head::clear): Declare.
	(dom_oracle::clear): Override.
	(path_oracle::clear): Override.

	gcc/testsuite/
	* gcc.dg/pr126856.c: New test.
---
 gcc/gimple-range-cache.cc       | 21 +++++++
 gcc/gimple-range-cache.h        |  3 +
 gcc/gimple-range-gori.cc        | 15 +++++
 gcc/gimple-range-gori.h         |  1 +
 gcc/gimple-range-infer.cc       | 31 +++++++++++
 gcc/gimple-range-infer.h        |  2 +
 gcc/gimple-range.cc             |  9 +++
 gcc/gimple-range.h              |  1 +
 gcc/testsuite/gcc.dg/pr126856.c | 16 ++++++
 gcc/tree-ssa-dce.cc             |  2 +
 gcc/tree-ssanames.cc            |  3 +
 gcc/value-query.cc              | 11 ++++
 gcc/value-query.h               |  2 +
 gcc/value-relation.cc           | 98 +++++++++++++++++++++++++++++++++
 gcc/value-relation.h            | 11 ++++
 15 files changed, 226 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/pr126856.c

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index a540a10ce58..0386b998117 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -381,6 +381,17 @@ block_range_cache::~block_range_cache ()
   bitmap_obstack_release (&m_bitmaps);
 }
 
+// Clear block info for NAME.
+
+void
+block_range_cache::clear (tree name)
+{
+  unsigned v = SSA_NAME_VERSION (name);
+  if (v >= m_ssa_ranges.length ())
+    return;
+  m_ssa_ranges[v] = NULL;
+}
+
 // Set the range for NAME on entry to block BB to R.
 // If it has not been accessed yet, allocate it first.
 
@@ -1982,3 +1993,13 @@ ranger_cache::apply_inferred_ranges (gimple *s)
     for (unsigned x = 0; x < infer.num (); x++)
       register_inferred_value (infer.range (x), infer.name (x), bb);
 }
+
+// Reset range info for NAME.
+
+void
+ranger_cache::reset_range_info (tree name)
+{
+  m_on_entry.clear (name);
+  m_globals.clear_range (name);
+  range_query::reset_range_info (name);
+}
diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h
index e01f35a548d..8a4185fc3e3 100644
--- a/gcc/gimple-range-cache.h
+++ b/gcc/gimple-range-cache.h
@@ -38,6 +38,7 @@ public:
   bool set_bb_range (tree name, const_basic_block bb, const vrange &v);
   bool get_bb_range (vrange &v, tree name, const_basic_block bb);
   bool bb_range_p (tree name, const_basic_block bb);
+  void clear (tree name);
 
   void dump (FILE *f);
   void dump (FILE *f, basic_block bb, bool print_varying = true);
@@ -120,6 +121,8 @@ public:
   void register_inferred_value (const vrange &r, tree name, basic_block bb);
   void apply_inferred_ranges (gimple *s);
 
+  void reset_range_info (tree name);
+
   void dump_bb (FILE *f, basic_block bb);
   virtual void dump (FILE *f) override;
 private:
diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 3bdc5305b49..d34c2b79a7c 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -295,6 +295,21 @@ range_def_chain::get_def_chain (tree name)
   return m_def_chain[v].bm;
 }
 
+// Clear def chain info for NAME.
+
+void
+range_def_chain::clear (tree name)
+{
+  unsigned v = SSA_NAME_VERSION (name);
+  if (v >= m_def_chain.length ())
+    return;
+
+  m_def_chain[v].ssa1 = 0;
+  m_def_chain[v].ssa2 = 0;
+  m_def_chain[v].bm = NULL;
+  get_def_chain (name);
+}
+
 // Dump what we know for basic block BB to file F.
 
 void
diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h
index d562c515a28..ab83d8f3dff 100644
--- a/gcc/gimple-range-gori.h
+++ b/gcc/gimple-range-gori.h
@@ -36,6 +36,7 @@ public:
   bool in_chain_p (tree name, tree def);
   bool chain_import_p (tree name, tree import);
   void register_dependency (tree name, tree ssa1, basic_block bb = NULL);
+  void clear (tree name);
   void dump (FILE *f, basic_block bb, const char *prefix = NULL);
 protected:
   bool has_def_chain (tree name);
diff --git a/gcc/gimple-range-infer.cc b/gcc/gimple-range-infer.cc
index 65c10ac1cb4..5f0f7efcc01 100644
--- a/gcc/gimple-range-infer.cc
+++ b/gcc/gimple-range-infer.cc
@@ -532,3 +532,34 @@ infer_range_manager::register_all_uses (tree name)
 	}
     }
 }
+
+// Clear all inferred ranges for NAME.
+
+void
+infer_range_manager::clear(tree name)
+{
+  if (!m_seen)
+    return;
+
+  // Check if this name has any inferred ranges.
+  unsigned v = SSA_NAME_VERSION (name);
+  if (!bitmap_bit_p (m_seen, v))
+     return;
+
+  // Check each basic block for an inferred range.
+  basic_block bb;
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      unsigned bbi = bb->index;
+      if (bbi >= m_on_exit.length ())
+	continue;
+      exit_range *ptr = m_on_exit[bbi].find_ptr (name);
+      if (ptr)
+	{
+	  bitmap_clear_bit (m_on_exit[bbi].m_names, v);
+	  ptr->name = NULL;
+	}
+    }
+
+  bitmap_clear_bit (m_seen, v);
+}
diff --git a/gcc/gimple-range-infer.h b/gcc/gimple-range-infer.h
index e2adeec8edf..ca95e121633 100644
--- a/gcc/gimple-range-infer.h
+++ b/gcc/gimple-range-infer.h
@@ -89,6 +89,7 @@ public:
   virtual bool has_range_p (basic_block, tree = NULL_TREE) { return false; }
   virtual bool maybe_adjust_range (vrange &, tree, basic_block)
       { return false; }
+  virtual void clear (tree) { }
 };
 
 // This class manages a list of inferred ranges for each basic block.
@@ -115,6 +116,7 @@ public:
   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);
+  virtual void clear (tree name);
 private:
   void add_range (tree name, gimple *s, const vrange &r);
   void add_nonzero (tree name, gimple *s);
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 37390c5df27..b221cfc5616 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -607,6 +607,15 @@ gimple_ranger::update_range_info (tree name, const vrange &r)
     }
 }
 
+// Reset range information for NAME.
+
+void
+gimple_ranger::reset_range_info (tree name)
+{
+  // Clearing the cache will also clear all the shared oracles.
+  m_cache.reset_range_info (name);
+}
+
 // This routine will export whatever global ranges are known to GCC
 // SSA_RANGE_NAME_INFO and SSA_NAME_PTR_INFO fields.
 
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index a74b48aafe6..003fede8334 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -65,6 +65,7 @@ public:
   void register_inferred_ranges (gimple *s);
   void register_transitive_inferred_ranges (basic_block bb);
   range_query &const_query ();
+  void reset_range_info (tree name);
 protected:
   bool fold_range_internal (vrange &r, gimple *s, tree name);
   struct prefill_frame
diff --git a/gcc/testsuite/gcc.dg/pr126856.c b/gcc/testsuite/gcc.dg/pr126856.c
new file mode 100644
index 00000000000..9f1d7734705
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr126856.c
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+__attribute__((noipa)) static int
+mpfr_scale2_bad (int exp)
+{
+    if (-1073 > exp || exp > 1025)
+      __builtin_unreachable();
+    if (exp < -1021)
+      __builtin_abort();
+    return exp;
+}
+int main ()
+{
+    if (mpfr_scale2_bad(499) != 499)
+    __builtin_abort();
+}
diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc
index 18bc851b2cd..a5391290c4d 100644
--- a/gcc/tree-ssa-dce.cc
+++ b/gcc/tree-ssa-dce.cc
@@ -2278,6 +2278,7 @@ simple_dce_from_worklist (bitmap worklist, bitmap need_eh_cleanup,
 	      for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
 		SET_PHI_ARG_DEF (phi, i, zero);
 	      update_stmt (phi);
+	      reset_flow_sensitive_info (def);
 	    }
 	  else
 	    remove_phi_node (&gsi, true);
@@ -2292,6 +2293,7 @@ simple_dce_from_worklist (bitmap worklist, bitmap need_eh_cleanup,
 	      tree zero = build_zero_cst (TREE_TYPE (def));
 	      gassign *new_stmt = gimple_build_assign (def, zero);
 	      gsi_replace (&gsi, new_stmt, true);
+	      reset_flow_sensitive_info (def);
 	    }
 	  else
 	    {
diff --git a/gcc/tree-ssanames.cc b/gcc/tree-ssanames.cc
index 9ad860df65a..8eac57f42cb 100644
--- a/gcc/tree-ssanames.cc
+++ b/gcc/tree-ssanames.cc
@@ -927,6 +927,9 @@ reset_flow_sensitive_info (tree name)
     }
   else
     SSA_NAME_RANGE_INFO (name) = NULL;
+
+  // Clear range info in the current range query.
+  get_range_query (cfun)->reset_range_info (name);
 }
 
 /* Clear all flow sensitive data from all statements and PHI definitions
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index decf4e4d0ac..17077eef9e8 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -78,6 +78,17 @@ range_query::update_range_info (tree, const vrange &)
 {
 }
 
+// Default for resetting range info for NAME is to clear the oracles.
+
+void
+range_query::reset_range_info (tree name)
+{
+  relation ().clear (name);
+  if (gori_ssa ())
+    gori_ssa ()->clear (name);
+  infer_oracle ().clear (name);
+}
+
 // If the range of expr EXPR at STMT is a single value, return it.
 // Otherwise return NULL_TREE.
 
diff --git a/gcc/value-query.h b/gcc/value-query.h
index 7756e431155..9932d7d493b 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -79,6 +79,8 @@ public:
   virtual void update_range_info (tree name);
   // Provide a specific range update to NAME.
   virtual void update_range_info (tree name, const vrange &r);
+  // Reset range information for NAME.
+  virtual void reset_range_info (tree name);
 
   inline class relation_oracle &relation () const  { return *m_relation; }
   void create_relation_oracle (bool do_trans_p = true);
diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc
index cc9e8e56c67..b4b65e6cdc8 100644
--- a/gcc/value-relation.cc
+++ b/gcc/value-relation.cc
@@ -621,6 +621,38 @@ equiv_oracle::register_initial_def (tree ssa)
   add_equiv_to_block (bb, equiv_set);
 }
 
+// Clear the equivalence lists and partial equivalencs for NAME.
+
+void
+equiv_oracle::clear (tree name)
+{
+  unsigned v = SSA_NAME_VERSION (name);
+  // Remove v from any equivalences.
+  if (bitmap_bit_p (m_equiv_set, v))
+    {
+      basic_block bb;
+      FOR_EACH_BB_FN (bb, cfun)
+	{
+	  unsigned bbi = bb->index;
+	  if (bbi >= m_equiv.length ())
+	    continue;
+	  if (!m_equiv[bbi])
+	    continue;
+	  equiv_chain *ptr = m_equiv[bbi]->find (v);
+	  if (ptr)
+	    {
+	      bitmap_clear_bit (ptr->m_names, v);
+	      bitmap_clear_bit (m_equiv[bbi]->m_names, v);
+	    }
+	}
+      bitmap_clear_bit (m_equiv_set, v);
+    }
+  // Eliminate any partial equivs.
+  if (v < m_partial.length ())
+    m_partial[v].members = NULL;
+}
+
+
 // Register an equivalence between SSA1 and SSA2 in block BB.
 // The equivalence oracle maintains a vector of equivalencies indexed by basic
 // block. When an equivalence between SSA1 and SSA2 is registered in block BB,
@@ -1078,6 +1110,56 @@ dom_oracle::~dom_oracle ()
   m_relations.release ();
 }
 
+// Remove any relations with NAME from this list.
+
+void
+relation_chain_head::clear (tree name)
+{
+  unsigned v = SSA_NAME_VERSION (name);
+  if (!m_names || !bitmap_bit_p (m_names, v))
+    return;
+
+  relation_chain *ptr, *last = NULL;;
+
+  for (ptr = m_head; ptr; ptr = ptr->m_next)
+    {
+      tree op1 = ptr->op1 ();
+      tree op2 = ptr->op2 ();
+      // Delink any elements with NAME.
+      if (op1 == name || op2 == name)
+	{
+	  if (!last)
+	    m_head = ptr->m_next;
+	  else
+	    last->m_next = ptr->m_next;
+	}
+      else
+	last = ptr;
+    }
+  // And remove name from the possible relations in this block bitfield.
+  bitmap_clear_bit (m_names, v);
+}
+
+// Remove any relations involving NAME from the DOM oracle
+
+void
+dom_oracle::clear (tree name)
+{
+  equiv_oracle::clear (name);
+  unsigned v = SSA_NAME_VERSION (name);
+  if (bitmap_bit_p (m_relation_set, v))
+    {
+      basic_block bb;
+      FOR_EACH_BB_FN (bb, cfun)
+	{
+	  if (bb->index >= (int)m_relations.length())
+	    continue;
+	  m_relations[bb->index].clear (name);
+	}
+      bitmap_clear_bit (m_relation_set, v);
+    }
+}
+
 // Register relation K between ssa_name OP1 and OP2 on STMT.
 // Return false if no new relation is added.
 
@@ -1728,6 +1810,22 @@ path_oracle::~path_oracle ()
   bitmap_obstack_release (&m_bitmaps);
 }
 
+// Clear any range info and relations associated with NAME.
+
+void
+path_oracle::clear (tree name)
+{
+  if (m_root)
+    m_root->clear (name);
+
+  m_relations.clear (name);
+
+  unsigned v = SSA_NAME_VERSION (name);
+  equiv_chain *ptr = m_equiv.find (v);
+  if (ptr)
+    bitmap_clear_bit (ptr->m_names, v);
+}
+
 // Return the equiv set for SSA, and if there isn't one, check for equivs
 // starting in block BB.
 
diff --git a/gcc/value-relation.h b/gcc/value-relation.h
index eed79c5e83d..d150b0ac5b2 100644
--- a/gcc/value-relation.h
+++ b/gcc/value-relation.h
@@ -110,6 +110,9 @@ public:
   relation_kind query (edge e, tree ssa1, tree ssa2);
   virtual relation_kind query (basic_block, tree, tree) { return VREL_VARYING; }
 
+  // Remove relations for an SSA_NAME
+  virtual void clear (tree) { }
+
   virtual void dump (FILE *, basic_block) const { }
   virtual void dump (FILE *) const  { }
   void debug () const;
@@ -174,6 +177,8 @@ public:
   relation_kind partial_equiv (tree ssa1, tree ssa2, tree *base = NULL) const;
   relation_kind query (basic_block, tree, tree) override;
   relation_kind query (basic_block, const_bitmap, const_bitmap) override;
+
+  virtual void clear (tree name);
   void dump (FILE *f, basic_block bb) const override;
   void dump (FILE *f) const override;
 
@@ -209,6 +214,7 @@ public:
   class relation_chain *m_head; // List of relations in block.
   int m_num_relations;		// Number of relations in block.
   relation_kind find_relation (const_bitmap b1, const_bitmap b2) const;
+  void clear (tree name);
 };
 
 // A relation oracle maintains a set of relations between ssa_names using the
@@ -234,6 +240,8 @@ public:
   relation_kind query (basic_block bb, const_bitmap b1, const_bitmap b2)
     final override;
 
+  virtual void clear (tree name);
+
   void dump (FILE *f, basic_block bb) const final override;
   void dump (FILE *f) const final override;
 protected:
@@ -284,6 +292,9 @@ public:
   relation_kind query (basic_block, const_bitmap, const_bitmap) final override;
   void reset_path (relation_oracle *oracle = NULL);
   void set_root_oracle (relation_oracle *oracle) { m_root = oracle; }
+
+  virtual void clear (tree name);
+
   void dump (FILE *, basic_block) const final override;
   void dump (FILE *) const final override;
 private:
-- 
2.45.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.