https://gcc.gnu.org/g:337ebeccfdaaea5549324e749ad503ac6008d860

commit r16-5323-g337ebeccfdaaea5549324e749ad503ac6008d860
Author: Andrew MacLeod <[email protected]>
Date:   Fri Nov 14 16:06:42 2025 -0500

    Turn PHI analyzer to a simple pre-pass
    
    Rather than having a dynamic analyzer around that is handcuffed by
    only global values, invoke it as a prepass in VRP and put all values it 
finds
    in the query's global cache via update_range_info.
    
            gcc/
            * gimple-range-fold.cc (fold_using_range::range_of_phi): Remove
            the PHI analysis query.
            * gimple-range-phi.cc (phi_analysis_object): Delete.
            (phi_analysis_initialize): Delete.
            (phi_analysis_finalize): Delete.
            (phi_analysis_available_p): Delete.
            (phi_analysis): Invoke a phi analyzer.
            (phi_analyzer::phi_analyzer): Preprocess all phi nodes and set
            global values for them in a query.
            (phi_analyzer::process_phi): Use query, and export any inital
            values found to the query.
            * gimple-range-phi.h (m_global): Delete.
            (phi_analysis_initialize): Delete.
            (phi_analysis_finalize): Delete.
            (phi_analysis_available_p): Delete.
            (phi_analysis): Change prototype.
            * tree-vrp.cc (execute_ranger_vrp): Call phi_analysis.
    
            gcc/testsuite/
            * gcc.dg/pr102983.c: Adjust final check.

Diff:
---
 gcc/gimple-range-fold.cc        |  28 ++---------
 gcc/gimple-range-phi.cc         | 101 ++++++++++++++++++----------------------
 gcc/gimple-range-phi.h          |  17 ++-----
 gcc/testsuite/gcc.dg/pr102983.c |   2 +-
 gcc/tree-vrp.cc                 |   3 +-
 5 files changed, 55 insertions(+), 96 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index d4481770d76e..63e114e4d044 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -1008,31 +1008,9 @@ fold_using_range::range_of_phi (vrange &r, gphi *phi, 
fur_source &src)
        }
     }
 
-  // If PHI analysis is available, see if there is an iniital range.
-  if (phi_analysis_available_p ()
-      && irange::supports_p (TREE_TYPE (phi_def)))
-    {
-      phi_group *g = (phi_analysis())[phi_def];
-      if (g && !(g->range ().varying_p ()))
-       {
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, "PHI GROUP query for ");
-             print_generic_expr (dump_file, phi_def, TDF_SLIM);
-             fprintf (dump_file, " found : ");
-             g->range ().dump (dump_file);
-             fprintf (dump_file, " and adjusted original range from :");
-             r.dump (dump_file);
-           }
-         r.intersect (g->range ());
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, " to :");
-             r.dump (dump_file);
-             fprintf (dump_file, "\n");
-           }
-       }
-    }
+  // Incorporate any global value.  If a PHI analysis phase was run, there may
+  // be a restricted global range already.  Query the range with no context
+  // to get a global range.
 
   // If SCEV is available, query if this PHI has any known values.
   if (scev_initialized_p ()
diff --git a/gcc/gimple-range-phi.cc b/gcc/gimple-range-phi.cc
index d9b583fe4fbe..45895209600c 100644
--- a/gcc/gimple-range-phi.cc
+++ b/gcc/gimple-range-phi.cc
@@ -37,41 +37,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-walk.h"
 #include "cfganal.h"
 
-// There can be only one running at a time.
-static phi_analyzer *phi_analysis_object = NULL;
-
-// Initialize a PHI analyzer with range query Q.
+// Invoke a phi analyzer.  It will process all the current PHI groups
+// and export any ranges found to set_range_info.
+// When finished, it will simply dispose of itself.
 
 void
-phi_analysis_initialize (range_query &q)
-{
-  gcc_checking_assert (!phi_analysis_object);
-  phi_analysis_object = new phi_analyzer (q);
-}
-
-// Terminate the current PHI analyzer.  if F is non-null, dump the tables
-
-void
-phi_analysis_finalize ()
-{
-  gcc_checking_assert (phi_analysis_object);
-  delete phi_analysis_object;
-  phi_analysis_object = NULL;
-}
-
-// Return TRUE is there is a PHI analyzer operating.
-bool
-phi_analysis_available_p ()
-{
-  return phi_analysis_object != NULL;
-}
-
-// Return the phi analyzer object.
-
-phi_analyzer &phi_analysis ()
+phi_analysis (range_query &q)
 {
-  gcc_checking_assert (phi_analysis_object);
-  return *phi_analysis_object;
+  phi_analyzer analyze (q);
 }
 
 // Initialize a phi_group from another group G.
@@ -254,16 +227,35 @@ phi_group::dump (FILE *f)
 
 // Construct a phi analyzer which uses range_query G to pick up values.
 
-phi_analyzer::phi_analyzer (range_query &g) : m_global (g), m_phi_groups 
(vNULL)
+phi_analyzer::phi_analyzer (range_query &query) : m_phi_groups (vNULL)
 {
   m_work.create (0);
   m_work.safe_grow (20);
 
   m_tab.create (0);
-//   m_tab.safe_grow_cleared (num_ssa_names + 100);
+  m_tab.safe_grow_cleared (num_ssa_names + 10);
+
   bitmap_obstack_initialize (&m_bitmaps);
   m_simple = BITMAP_ALLOC (&m_bitmaps);
   m_current = BITMAP_ALLOC (&m_bitmaps);
+
+  basic_block bb;
+  gphi_iterator gphi;
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "PHI ANALYZER : processing PHIS.\n");
+
+  // Process each PHI node to see if it belongs in a group with others.
+  // Then calculate an initial value for the group.
+  FOR_EACH_BB_FN (bb, cfun)
+    {
+      for (gphi = gsi_start_nonvirtual_phis (bb);
+          !gsi_end_p (gphi);
+          gsi_next_nonvirtual_phi (&gphi))
+       process_phi (gphi.phi (), query);
+    }
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "PHI ANALYZER : Finished processing PHIS.\n");
 }
 
 // Destruct a PHI analyzer.
@@ -308,35 +300,33 @@ phi_analyzer::operator[] (tree name)
     return NULL;
 
   unsigned v = SSA_NAME_VERSION (name);
-  // Already been processed and not part of a group.
-  if (bitmap_bit_p (m_simple, v))
+  if (v >= m_tab.length ())
     return NULL;
-
-  if (v >= m_tab.length () || !m_tab[v])
-    {
-      process_phi (as_a<gphi *> (SSA_NAME_DEF_STMT (name)));
-      if (bitmap_bit_p (m_simple, v))
-       return  NULL;
-     // If m_simple bit isn't set, and process_phi didn't allocated the table
-     // no group was created, so return NULL.
-     if (v >= m_tab.length ())
-      return NULL;
-    }
   return m_tab[v];
 }
 
-// Process phi node PHI to see if it is part of a group.
+// Process phi node PHI to see if it is part of a group.  Use QUERY
+// to deteremine ranges.
 
 void
-phi_analyzer::process_phi (gphi *phi)
+phi_analyzer::process_phi (gphi *phi, range_query &query)
 {
-  gcc_checking_assert (!group (gimple_phi_result (phi)));
+  tree def = gimple_phi_result (phi);
+  unsigned v = SSA_NAME_VERSION (def);
+
+  gcc_checking_assert (v < m_tab.length ());
+  // If this is already on a group, or identified as a simple phi, or
+  // not an irange, do not process it.
+  if (m_tab[v] || bitmap_bit_p (m_simple, v)
+      || !irange::supports_p (TREE_TYPE (def)))
+    return;
+
   bool cycle_p = true;
 
   // Start with the LHS of the PHI in the worklist.
   unsigned x;
   m_work.truncate (0);
-  m_work.safe_push (gimple_phi_result (phi));
+  m_work.safe_push (def);
   unsigned phi_count = 1;
   bitmap_clear (m_current);
 
@@ -447,7 +437,7 @@ phi_analyzer::process_phi (gphi *phi)
       // If there is an symbolic initializer as well, include it here.
       if (valid && init_idx != -1)
        {
-         if (m_global.range_on_edge (init_sym, m_ext_edge[init_idx],
+         if (query.range_on_edge (init_sym, m_ext_edge[init_idx],
                                      m_external[init_idx]))
            init_range.union_ (init_sym);
          else
@@ -457,7 +447,7 @@ phi_analyzer::process_phi (gphi *phi)
        {
          // Try to create a group based on m_current. If a result comes back
          // with a range that isn't varying, create the group.
-         phi_group cyc (m_current, init_range, mod, &m_global);
+         phi_group cyc (m_current, init_range, mod, &query);
          if (!cyc.range ().varying_p ())
            {
              g = new phi_group (cyc);
@@ -490,9 +480,6 @@ phi_analyzer::process_phi (gphi *phi)
       return;
     }
 
-  if (num_ssa_names >= m_tab.length ())
-    m_tab.safe_grow_cleared (num_ssa_names + 100);
-
   // Now set all entries in the group to this record.
   unsigned i;
   bitmap_iterator bi;
@@ -501,6 +488,8 @@ phi_analyzer::process_phi (gphi *phi)
       // Can't be in more than one group.
       gcc_checking_assert (m_tab[i] == NULL);
       m_tab[i] = g;
+      // Set the new range in the range query.
+      query.update_range_info (ssa_name (i), g->range ());
     }
   // Allocate a new bitmap for the next time as the original one is now part
   // of the new phi group.
diff --git a/gcc/gimple-range-phi.h b/gcc/gimple-range-phi.h
index ea5750520c24..34001f738da7 100644
--- a/gcc/gimple-range-phi.h
+++ b/gcc/gimple-range-phi.h
@@ -81,8 +81,7 @@ public:
   void dump (FILE *f);
 protected:
   phi_group *group (tree name) const;
-  void process_phi (gphi *phi);
-  range_query &m_global;
+  void process_phi (gphi *phi, range_query &query);
   vec<tree> m_work;
 
   bitmap m_simple;       // Processed, not part of a group.
@@ -92,16 +91,10 @@ protected:
   bitmap_obstack m_bitmaps;
 };
 
-// These are the APIs to start and stop a phi analyzerin a SCEV like manner.
-// There can only be one operating at any given time.
-// When initialized, a range-query if provided to do lookups of values for
-// PHIs and to evaluate modifier and initial value statements.
-// To avoid problems, this should be some form of constant query, like
-// global_range_query or better yet a const_query from a functioning ranger.
+// Invoke a phi analyzer.  It will process all the current PHI nodes and try
+// to form groups with initial values. Then export any ranges found
+// to set_range_info.  When finished, it will simply dispose of itself.
 
-bool phi_analysis_available_p ();
-phi_analyzer &phi_analysis ();
-void phi_analysis_initialize (range_query &);
-void phi_analysis_finalize ();
+void phi_analysis (range_query &q);
 
 #endif // GCC_SSA_RANGE_PHI_H
diff --git a/gcc/testsuite/gcc.dg/pr102983.c b/gcc/testsuite/gcc.dg/pr102983.c
index ded748af08a3..1b0e5c7587d5 100644
--- a/gcc/testsuite/gcc.dg/pr102983.c
+++ b/gcc/testsuite/gcc.dg/pr102983.c
@@ -18,4 +18,4 @@ int main() {
   }
 }
 
-/* { dg-final { scan-tree-dump-times "Global Exported: c_.*1, 1" 1 "evrp" } } 
*/
+/* { dg-final { scan-tree-dump-not "if \\(c_"  "evrp" } } */
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index cad1a24ab339..b173ed263866 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -1094,8 +1094,8 @@ execute_ranger_vrp (struct function *fun, bool final_p)
 
   set_all_edges_as_executable (fun);
   gimple_ranger *ranger = enable_ranger (fun, false);
+  phi_analysis (*ranger);
   rvrp_folder folder (ranger, final_p);
-  phi_analysis_initialize (ranger->const_query ());
   folder.substitute_and_fold ();
   // Ensure the cache in SCEV has been cleared before processing
   // globals to be removed.
@@ -1149,7 +1149,6 @@ execute_ranger_vrp (struct function *fun, bool final_p)
        }
     }
 
-  phi_analysis_finalize ();
   disable_ranger (fun);
   scev_finalize ();
   loop_optimizer_finalize ();

Reply via email to