[gcc r15-1543] Change fast VRP algorithm

Andrew Macleod amacleod@gcc.gnu.org
Fri Jun 21 13:01:55 GMT 2024


https://gcc.gnu.org/g:68532d3c63725777aaa63b9ac2e4a086c6359bfa

commit r15-1543-g68532d3c63725777aaa63b9ac2e4a086c6359bfa
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Mon Jun 17 11:32:51 2024 -0400

    Change fast VRP algorithm
    
    Change the fast VRP algorithm to track contextual ranges active within
    each basic block.
    
            * gimple-range.cc (dom_ranger::dom_ranger): Create a block
            vector.
            (dom_ranger::~dom_ranger): Dispose of the block vector.
            (dom_ranger::edge_range): Delete.
            (dom_ranger::range_on_edge): Combine range in src BB with any
            range gori_nme_on_edge returns.
            (dom_ranger::range_in_bb): Combine global range with any active
            contextual range for an ssa-name.
            (dom_ranger::range_of_stmt): Fix non-ssa LHS case, use
            fur_depend for folding so relations can be registered.
            (dom_ranger::maybe_push_edge): Delete.
            (dom_ranger::pre_bb): Create incoming contextual range vector.
            (dom_ranger::post_bb): Free contextual range vector.
            * gimple-range.h (dom_ranger::edge_range): Delete.
            (dom_ranger::m_e0): Delete.
            (dom_ranger::m_e1): Delete.
            (dom_ranger::m_bb): New.
            (dom_ranger::m_pop_list): Delete.
            * tree-vrp.cc (execute_fast_vrp): Enable relation oracle.

Diff:
---
 gcc/gimple-range.cc | 232 +++++++++++++++++++---------------------------------
 gcc/gimple-range.h  |   8 +-
 gcc/tree-vrp.cc     |   2 +
 3 files changed, 90 insertions(+), 152 deletions(-)

diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index f3e4ec2d249..4e507485f5e 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -918,7 +918,15 @@ assume_query::dump (FILE *f)
 }
 
 // ---------------------------------------------------------------------------
-
+//
+// The DOM based ranger assumes a single DOM walk through the IL, and is
+// used by the fvrp_folder as a fast VRP.
+// During the dom walk, the current block has an ssa_lazy_cache pointer
+// m_bb[bb->index] which represents all the cumulative contextual ranges
+// active in the block.
+// These ranges are pure static ranges generated by branches, and must be
+// combined with the equivlaent global range to produce the final range.
+// A NULL pointer means there are no contextual ranges.
 
 // Create a DOM based ranger for use by a DOM walk pass.
 
@@ -926,11 +934,8 @@ dom_ranger::dom_ranger () : m_global ()
 {
   m_freelist.create (0);
   m_freelist.truncate (0);
-  m_e0.create (0);
-  m_e0.safe_grow_cleared (last_basic_block_for_fn (cfun));
-  m_e1.create (0);
-  m_e1.safe_grow_cleared (last_basic_block_for_fn (cfun));
-  m_pop_list = BITMAP_ALLOC (NULL);
+  m_bb.create (0);
+  m_bb.safe_grow_cleared (last_basic_block_for_fn (cfun));
   if (dump_file && (param_ranger_debug & RANGER_DEBUG_TRACE))
     tracer.enable_trace ();
 }
@@ -945,9 +950,7 @@ dom_ranger::~dom_ranger ()
       fprintf (dump_file, "=========================:\n");
       m_global.dump (dump_file);
     }
-  BITMAP_FREE (m_pop_list);
-  m_e1.release ();
-  m_e0.release ();
+  m_bb.release ();
   m_freelist.release ();
 }
 
@@ -973,6 +976,7 @@ dom_ranger::range_of_expr (vrange &r, tree expr, gimple *s)
 	  fprintf (dump_file, "\n");
     }
 
+  // If there is a statement, return the range in that statements block.
   if (s)
     range_in_bb (r, gimple_bb (s), expr);
   else
@@ -983,37 +987,15 @@ dom_ranger::range_of_expr (vrange &r, tree expr, gimple *s)
   return true;
 }
 
-
-// Return TRUE and the range if edge E has a range set for NAME in
-// block E->src.
-
-bool
-dom_ranger::edge_range (vrange &r, edge e, tree name)
-{
-  bool ret = false;
-  basic_block bb = e->src;
-
-  // Check if BB has any outgoing ranges on edge E.
-  ssa_lazy_cache *out = NULL;
-  if (EDGE_SUCC (bb, 0) == e)
-    out = m_e0[bb->index];
-  else if (EDGE_SUCC (bb, 1) == e)
-    out = m_e1[bb->index];
-
-  // If there is an edge vector and it has a range, pick it up.
-  if (out && out->has_range (name))
-    ret = out->get_range (r, name);
-
-  return ret;
-}
-
-
 // Return the range of EXPR on edge E in R.
 // Return false if no range can be calculated.
 
 bool
 dom_ranger::range_on_edge (vrange &r, edge e, tree expr)
 {
+  if (!gimple_range_ssa_p (expr))
+    return get_tree_range (r, expr, NULL);
+
   basic_block bb = e->src;
   unsigned idx;
   if ((idx = tracer.header ("range_on_edge ")))
@@ -1023,11 +1005,10 @@ dom_ranger::range_on_edge (vrange &r, edge e, tree expr)
       fputc ('\n',dump_file);
     }
 
-  if (!gimple_range_ssa_p (expr))
-    return get_tree_range (r, expr, NULL);
-
-  if (!edge_range (r, e, expr))
-    range_in_bb (r, bb, expr);
+  range_in_bb (r, bb, expr);
+  value_range vr(TREE_TYPE (expr));
+  if (gori_name_on_edge (vr, expr, e, this))
+    r.intersect (vr);
 
   if (idx)
     tracer.trailer (idx, " ", true, expr, r);
@@ -1039,35 +1020,23 @@ dom_ranger::range_on_edge (vrange &r, edge e, tree expr)
 void
 dom_ranger::range_in_bb (vrange &r, basic_block bb, tree name)
 {
-  basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (name));
-  // Loop through dominators until we get to the entry block, or we find
-  // either the defintion block for NAME, or a single pred edge with a range.
-  while (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun))
+  // Start with the global value.
+  m_global.range_of_expr (r, name);
+
+  // If there is a contextual range, intersect it with the global range
+  ssa_lazy_cache *context = m_bb[bb->index];
+  if (context && context->has_range (name))
     {
-      // If we hit the deifntion block, pick up the global value.
-      if (bb == def_bb)
-	{
-	  m_global.range_of_expr (r, name);
-	  return;
-	}
-      // If its a single pred, check the outgoing range of the edge.
-      if (EDGE_COUNT (bb->preds) == 1
-	  && edge_range (r, EDGE_PRED (bb, 0), name))
-	return;
-      // Otherwise move up to the dominator, and check again.
-      bb = get_immediate_dominator (CDI_DOMINATORS, bb);
+      value_range cr (TREE_TYPE (name));
+      context->get_range (cr, name);
+      r.intersect (cr);
     }
-  m_global.range_of_expr (r, name);
 }
 
-
 // Calculate the range of NAME, as the def of stmt S and return it in R.
-// Return FALSE if no range cqn be calculated.
+// Return FALSE if no range can be calculated.
 // Also set the global range for NAME as this should only be called within
 // the def block during a DOM walk.
-// Outgoing edges were pre-calculated, so when we establish a global defintion
-// check if any outgoing edges hav ranges that can be combined with the
-// global.
 
 bool
 dom_ranger::range_of_stmt (vrange &r, gimple *s, tree name)
@@ -1075,9 +1044,10 @@ dom_ranger::range_of_stmt (vrange &r, gimple *s, tree name)
   unsigned idx;
   bool ret;
   if (!name)
-    name = gimple_range_ssa_p (gimple_get_lhs (s));
+    name = gimple_get_lhs (s);
 
-  gcc_checking_assert (!name || name == gimple_get_lhs (s));
+  if (name && !gimple_range_ssa_p (name))
+    return get_tree_range (r, name, NULL);
 
   if ((idx = tracer.header ("range_of_stmt ")))
     print_gimple_stmt (dump_file, s, 0, TDF_SLIM);
@@ -1091,9 +1061,13 @@ dom_ranger::range_of_stmt (vrange &r, gimple *s, tree name)
       return ret;
     }
 
+  // Fold using a fur_depend object so that relations are registered.
+  fold_using_range f;
+  fur_depend src (s, this);
+  ret = f.fold_stmt (r, s, src, name);
+
   // If there is a new calculated range and it is not varying, set
   // a global range.
-  ret = fold_range (r, s, this);
   if (ret && name && m_global.merge_range (name, r) && !r.varying_p ())
     {
       if (set_range_info (name, r) && dump_file)
@@ -1104,115 +1078,81 @@ dom_ranger::range_of_stmt (vrange &r, gimple *s, tree name)
 	  r.dump (dump_file);
 	  fputc ('\n', dump_file);
 	}
-      basic_block bb = gimple_bb (s);
-      unsigned bbi = bb->index;
-      value_range vr (TREE_TYPE (name));
-      // If there is a range on edge 0, update it.
-      if (m_e0[bbi] && m_e0[bbi]->has_range (name))
-	{
-	  if (m_e0[bbi]->merge_range (name, r) && dump_file
-	      && (dump_flags & TDF_DETAILS))
-	    {
-	      fprintf (dump_file, "Outgoing range for ");
-	      print_generic_expr (dump_file, name, TDF_SLIM);
-	      fprintf (dump_file, " updated on edge %d->%d : ", bbi,
-		       EDGE_SUCC (bb, 0)->dest->index);
-	      if (m_e0[bbi]->get_range (vr, name))
-		vr.dump (dump_file);
-	      fputc ('\n', dump_file);
-	    }
-	}
-      // If there is a range on edge 1, update it.
-      if (m_e1[bbi] && m_e1[bbi]->has_range (name))
-	{
-	  if (m_e1[bbi]->merge_range (name, r) && dump_file
-	      && (dump_flags & TDF_DETAILS))
-	    {
-	      fprintf (dump_file, "Outgoing range for ");
-	      print_generic_expr (dump_file, name, TDF_SLIM);
-	      fprintf (dump_file, " updated on edge %d->%d : ", bbi,
-		       EDGE_SUCC (bb, 1)->dest->index);
-	      if (m_e1[bbi]->get_range (vr, name))
-		vr.dump (dump_file);
-	      fputc ('\n', dump_file);
-	    }
-	}
     }
   if (idx)
     tracer.trailer (idx, " ", ret, name, r);
   return ret;
 }
 
-// Check if GORI has an ranges on edge E.  If there re, store them in
-// either the E0 or E1 vector based on EDGE_0.
-// If there are no ranges, put the empty lazy_cache entry on the freelist
-// for use next time.
+// Preprocess block BB.  If there is a single predecessor, start with any
+// contextual ranges on the incoming edge, otherwise the initial list
+// of ranges i empty for this block.  Then Merge in any contextual ranges
+// from the dominator block.  Tihs will become the contextual ranges
+// that apply to this block.
 
 void
-dom_ranger::maybe_push_edge (edge e, bool edge_0)
+dom_ranger::pre_bb (basic_block bb)
 {
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "#FVRP entering BB %d\n", bb->index);
+
+  m_bb[bb->index] = NULL;
+  basic_block dom_bb  = get_immediate_dominator (CDI_DOMINATORS, bb);
+
   ssa_lazy_cache *e_cache;
   if (!m_freelist.is_empty ())
     e_cache = m_freelist.pop ();
   else
     e_cache = new ssa_lazy_cache;
-  gori_on_edge (*e_cache, e, this);
-  if (e_cache->empty_p ())
-    m_freelist.safe_push (e_cache);
-  else
+  gcc_checking_assert (e_cache->empty_p ());
+
+  // If there is a single pred, check if there are any ranges on
+  // the edge and start with those.
+  if (single_pred_p (bb))
     {
-      if (edge_0)
-	m_e0[e->src->index] = e_cache;
-      else
-	m_e1[e->src->index] = e_cache;
+      gori_on_edge (*e_cache, EDGE_PRED (bb, 0), this);
+      if (!e_cache->empty_p () && dump_file && (dump_flags & TDF_DETAILS))
+	{
+	  fprintf (dump_file, "\nEdge ranges BB %d->%d\n",
+		   EDGE_PRED (bb, 0)->src->index, bb->index);
+	  e_cache->dump(dump_file);
+	}
     }
-}
+  // If the dominator had any ranges registered, integrate those.
+  if (dom_bb && m_bb [dom_bb->index])
+    e_cache->merge (*(m_bb[dom_bb->index]));
 
-// Preprocess block BB.  If there are any outgoing edges, precalculate
-// the outgoing ranges and store them.   Note these are done before
-// we process the block, so global values have not been set yet.
-// These are "pure" outgoing ranges inflicted by the condition.
+  // If there are no ranges, this block has no contextual ranges.
+  if (e_cache->empty_p ())
+    m_freelist.safe_push (e_cache);
+  else
+    m_bb[bb->index] = e_cache;
 
-void
-dom_ranger::pre_bb (basic_block bb)
-{
   if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "#FVRP entering BB %d\n", bb->index);
-
-  // Next, see if this block needs outgoing edges calculated.
-  gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
-  if (!gsi_end_p (gsi))
     {
-      gimple *s = gsi_stmt (gsi);
-      if (is_a<gcond *> (s) && gimple_range_op_handler::supported_p (s))
+      if (m_bb[bb->index])
 	{
-	  maybe_push_edge (EDGE_SUCC (bb, 0), true);
-	  maybe_push_edge (EDGE_SUCC (bb, 1), false);
-
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      if (m_e0[bb->index])
-		{
-		  fprintf (dump_file, "\nEdge ranges BB %d->%d\n",
-			   bb->index, EDGE_SUCC (bb, 0)->dest->index);
-		  m_e0[bb->index]->dump(dump_file);
-		}
-	      if (m_e1[bb->index])
-		{
-		  fprintf (dump_file, "\nEdge ranges BB %d->%d\n",
-			   bb->index, EDGE_SUCC (bb, 1)->dest->index);
-		  m_e1[bb->index]->dump(dump_file);
-		}
-	    }
+	  fprintf (dump_file, "all contextual ranges active:\n");
+	  m_bb[bb->index]->dump (dump_file);
 	}
+      else
+	fprintf (dump_file, " NO contextual ranges active:\n");
     }
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "#FVRP DONE entering BB %d\n", bb->index);
 }
 
 // Perform any post block processing.
 
 void
-dom_ranger::post_bb (basic_block)
+dom_ranger::post_bb (basic_block bb)
 {
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    fprintf (dump_file, "#FVRP POST BB %d\n", bb->index);
+  // If there were contextual ranges, clear them and put the
+  // object on the freelist.
+  if (m_bb[bb->index])
+    {
+      m_bb[bb->index]->clear ();
+      m_freelist.safe_push (m_bb[bb->index]);
+      m_bb[bb->index] = NULL;
+    }
 }
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index 180090bed15..91177567947 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -112,19 +112,15 @@ public:
   virtual bool range_on_edge (vrange &r, edge e, tree expr) override;
   virtual bool range_of_stmt (vrange &r, gimple *s, tree name = NULL) override;
 
-  bool edge_range (vrange &r, edge e, tree name);
-  void range_in_bb (vrange &r, basic_block bb, tree name);
 
   void pre_bb (basic_block bb);
   void post_bb (basic_block bb);
 protected:
+  void range_in_bb (vrange &r, basic_block bb, tree name);
   DISABLE_COPY_AND_ASSIGN (dom_ranger);
-  void maybe_push_edge (edge e, bool edge_0);
   ssa_cache m_global;
   vec<ssa_lazy_cache *> m_freelist;
-  vec<ssa_lazy_cache *> m_e0;
-  vec<ssa_lazy_cache *> m_e1;
-  bitmap m_pop_list;
+  vec<ssa_lazy_cache *> m_bb;
   range_tracer tracer;
 };
 #endif // GCC_GIMPLE_RANGE_H
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index a3b1a5cd337..6e96b639b70 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -1284,11 +1284,13 @@ execute_fast_vrp (struct function *fun, bool final_p)
 
   gcc_checking_assert (!fun->x_range_query);
   fun->x_range_query = &dr;
+  get_range_query (fun)->create_relation_oracle ();
 
   folder.substitute_and_fold ();
   if (folder.m_unreachable)
     folder.m_unreachable->remove ();
 
+  get_range_query (fun)->destroy_relation_oracle ();
   fun->x_range_query = NULL;
   return 0;
 }


More information about the Gcc-cvs mailing list