]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Turn PHI analyzer to a simple pre-pass
authorAndrew MacLeod <amacleod@redhat.com>
Fri, 14 Nov 2025 21:06:42 +0000 (16:06 -0500)
committerAndrew MacLeod <amacleod@redhat.com>
Sun, 16 Nov 2025 22:20:41 +0000 (17:20 -0500)
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.

gcc/gimple-range-fold.cc
gcc/gimple-range-phi.cc
gcc/gimple-range-phi.h
gcc/testsuite/gcc.dg/pr102983.c
gcc/tree-vrp.cc

index d4481770d76ef16ae3750faa5626d95b17fef43c..63e114e4d044880be781bcd183e43ba3fee73f82 100644 (file)
@@ -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 ()
index d9b583fe4fbe4ef97351aa2b32cc68544e941cef..45895209600c5d0640243adc603691c6c3736dec 100644 (file)
@@ -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.
index ea5750520c2416ac28ecf5fa867b217340496624..34001f738da715b443546db63c46905a1a91edc3 100644 (file)
@@ -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
index ded748af08a315f3554e61b81c2abc10c51eaebf..1b0e5c7587d593103320dfffedbb2bbc178843dc 100644 (file)
@@ -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" } } */
index cad1a24ab339a45819ed77708844686fa6b3bcb2..b173ed263866cea9007613dfb8463ddcb6627068 100644 (file)
@@ -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 ();