[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