public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/aldyh/heads/ranger-staging)] Add iterative update
@ 2020-09-19 13:34 Andrew Macleod
0 siblings, 0 replies; only message in thread
From: Andrew Macleod @ 2020-09-19 13:34 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:30a7a71c4a14536cb89b83c43a7f0e2dd9b1b777
commit 30a7a71c4a14536cb89b83c43a7f0e2dd9b1b777
Author: Andrew MacLeod <amacleod@redhat.com>
Date: Sat Sep 19 09:34:06 2020 -0400
Add iterative update
Diff:
---
gcc/gimple-range-cache.cc | 246 ++++++++++++++++++++++++++++++++++++++++++----
gcc/gimple-range-cache.h | 13 ++-
gcc/gimple-range.h | 3 +-
3 files changed, 238 insertions(+), 24 deletions(-)
diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 777ab564727..77625d23bfa 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -450,24 +450,51 @@ ssa_global_cache::dump (FILE *f)
// --------------------------------------------------------------------------
-ranger_cache::ranger_cache ()
+ranger_cache::ranger_cache (range_query &q) : query (q)
{
m_workback.create (0);
m_workback.safe_grow_cleared (last_basic_block_for_fn (cfun));
m_update_list.create (0);
m_update_list.safe_grow_cleared (last_basic_block_for_fn (cfun));
m_update_list.truncate (0);
+ m_poor_value_list.create (0);
+ m_poor_value_list.safe_grow_cleared (20);
+ m_poor_value_list.truncate (0);
}
ranger_cache::~ranger_cache ()
{
+ m_poor_value_list.release ();
m_workback.release ();
m_update_list.release ();
}
+#define DEBUG_CACHE (dump_file && flag_evrp_mode == EVRP_MODE_RVRP_DEBUG)
+
+// Push a request for a new lookup in block BB of name. Return true if
+// the requiest is actually made (ie, isn't a duplicate)
+
+bool
+ranger_cache::push_poor_value (basic_block bb, tree name)
+{
+ if (m_poor_value_list.length ())
+ {
+ // Don't push anything else to the same block. IF there are multiple
+ // things required, another request will come during a later evaluation
+ // and this prevents oscillation building uneccessary depth.
+ if ((m_poor_value_list.last ()).bb == bb)
+ return false;
+ }
+
+ struct update_record rec;
+ rec.bb = bb;
+ rec.calc = name;
+ m_poor_value_list.safe_push (rec);
+ return true;
+}
// Provide lookup for the gori-computes class to access the best known range
-// of an ssa_name in any given basic block. NOte this does no additonal
+// of an ssa_name in any given basic block. Note this does no additonal
// lookups, just accesses the data that is already known.
void
@@ -476,9 +503,43 @@ ranger_cache::ssa_range_in_bb (irange &r, tree name, basic_block bb)
gimple *s = SSA_NAME_DEF_STMT (name);
basic_block def_bb = ((s && gimple_bb (s)) ? gimple_bb (s) :
ENTRY_BLOCK_PTR_FOR_FN (cfun));
- if (bb == def_bb || !m_on_entry.get_bb_range (r, name, bb))
+ if (bb == def_bb)
{
- // Try to pick up any known value first.
+ // NAME is defined in this block, so request its current value
+ if (!m_globals.get_global_range (r, name))
+ {
+ // If it doesn't have a value calculated, it means its a "poor" value
+ // being used in some calculation. Queue it up as a poor value to
+ // be improved later.
+ r = gimple_range_global (name);
+ if (push_poor_value (bb, name))
+ {
+ if (DEBUG_CACHE)
+ {
+ fprintf (dump_file,
+ "*CACHE* no global def in bb %d for ", bb->index);
+ print_generic_expr (dump_file, name, TDF_SLIM);
+ fprintf (dump_file, " depth : %d\n",
+ m_poor_value_list.length ());
+ }
+ }
+ }
+ }
+ // Look for the on-entry value of name in BB from the cache.
+ else if (!m_on_entry.get_bb_range (r, name, bb))
+ {
+ // If it has no entry then mark this as a poor value.
+ if (push_poor_value (bb, name))
+ {
+ if (DEBUG_CACHE)
+ {
+ fprintf (dump_file,
+ "*CACHE* no on entry range in bb %d for ", bb->index);
+ print_generic_expr (dump_file, name, TDF_SLIM);
+ fprintf (dump_file, " depth : %d\n", m_poor_value_list.length ());
+ }
+ }
+ // Try to pick up any known global value as a best guess for now.
if (!m_globals.get_global_range (r, name))
r = gimple_range_global (name);
}
@@ -511,7 +572,7 @@ ranger_cache::block_range (irange &r, basic_block bb, tree name, bool calc)
{
// If we get to the entry block, this better be a default def
// or range_on_entry was called for a block not dominated by
- // the def. This would be a bug.
+ // the def.
gcc_checking_assert (SSA_NAME_IS_DEFAULT_DEF (name));
def_bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
}
@@ -535,7 +596,6 @@ ranger_cache::add_to_update (basic_block bb)
m_update_list.quick_push (bb);
}
-#define DEBUG_CACHE (dump_file && flag_evrp_mode == EVRP_MODE_RVRP_DEBUG)
// If there is anything in the iterative update_list, continue
// processing NAME until the list of blocks is empty.
@@ -559,32 +619,76 @@ ranger_cache::iterative_cache_update (tree name)
while (m_update_list.length () > 0)
{
bb = m_update_list.pop ();
-if (DEBUG_CACHE) fprintf (dump_file, "FWD visiting block %d\n", bb->index);
-
gcc_assert (m_on_entry.get_bb_range (current_range, name, bb));
+
// Calculate the "new" range on entry by unioning the pred edges..
new_range.set_undefined ();
FOR_EACH_EDGE (e, ei, bb->preds)
{
+ if (DEBUG_CACHE)
+ fprintf (dump_file, " edge %d->%d :", e->src->index, bb->index);
// Get whatever range we can for this edge
if (!outgoing_edge_range_p (e_range, e, name))
- ssa_range_in_bb (e_range, name, e->src);
+ {
+ ssa_range_in_bb (e_range, name, e->src);
+ if (DEBUG_CACHE)
+ {
+ fprintf (dump_file, "No outgoing edge range, picked up ");
+ e_range.dump(dump_file);
+ fprintf (dump_file, "\n");
+ }
+ }
+ else
+ {
+ if (DEBUG_CACHE)
+ {
+ fprintf (dump_file, "outgoing range :");
+ e_range.dump(dump_file);
+ fprintf (dump_file, "\n");
+ }
+ }
new_range.union_ (e_range);
if (new_range.varying_p ())
break;
}
+
+ if (DEBUG_CACHE)
+ {
+ fprintf (dump_file, "FWD visiting block %d for ", bb->index);
+ print_generic_expr (dump_file, name, TDF_SLIM);
+ fprintf (dump_file, " starting range : ");
+ current_range.dump (dump_file);
+ fprintf (dump_file, "\n");
+ }
+
// If the range on entry has changed, update it.
if (new_range != current_range)
{
-if (DEBUG_CACHE) { fprintf (dump_file, " updating range from "); current_range.dump (dump_file); fprintf (dump_file, " to"); new_range.dump (dump_file); fprintf (dump_file, "\n"); }
+ if (DEBUG_CACHE)
+ {
+ fprintf (dump_file, " Updating range to ");
+ new_range.dump (dump_file);
+ fprintf (dump_file, "\n Updating blocks :");
+ }
m_on_entry.set_bb_range (name, bb, new_range);
// Mark each successor that has a range to re-check it's range
FOR_EACH_EDGE (e, ei, bb->succs)
if (m_on_entry.bb_range_p (name, e->dest))
- add_to_update (e->dest);
+ {
+ if (DEBUG_CACHE)
+ fprintf (dump_file, " bb%d",e->dest->index);
+ add_to_update (e->dest);
+ }
+ if (DEBUG_CACHE)
+ fprintf (dump_file, "\n");
}
}
-if (DEBUG_CACHE) fprintf (dump_file, "DONE visiting blocks \n\n");
+ if (DEBUG_CACHE)
+ {
+ fprintf (dump_file, "DONE visiting blocks for ");
+ print_generic_expr (dump_file, name, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
}
// Make sure that the range-on-entry cache for NAME is set for block BB.
@@ -598,6 +702,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
edge e;
int_range_max block_result;
int_range_max undefined;
+ unsigned poor_list_start = m_poor_value_list.length ();
// At this point we shouldnt be looking at the def, entry or exit block.
gcc_checking_assert (bb != def_bb && bb != ENTRY_BLOCK_PTR_FOR_FN (cfun) &&
@@ -616,17 +721,31 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
m_on_entry.set_bb_range (name, bb, undefined);
gcc_checking_assert (m_update_list.length () == 0);
-if (DEBUG_CACHE) { fprintf (dump_file, "\n"); print_generic_expr (dump_file, name, TDF_SLIM); fprintf (dump_file, " : "); }
+ if (DEBUG_CACHE)
+ {
+ fprintf (dump_file, "\n");
+ print_generic_expr (dump_file, name, TDF_SLIM);
+ fprintf (dump_file, " : ");
+ }
while (m_workback.length () > 0)
{
basic_block node = m_workback.pop ();
-if (DEBUG_CACHE) fprintf (dump_file, "BACK visiting block %d\n", node->index);
+ if (DEBUG_CACHE)
+ {
+ fprintf (dump_file, "BACK visiting block %d for ", node->index);
+ print_generic_expr (dump_file, name, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
FOR_EACH_EDGE (e, ei, node->preds)
- {
+ {
basic_block pred = e->src;
int_range_max r;
+
+ if (DEBUG_CACHE)
+ fprintf (dump_file, " %d->%d ",e->src->index, e->dest->index);
+
// If the pred block is the def block add this BB to update list.
if (pred == def_bb)
{
@@ -637,29 +756,116 @@ if (DEBUG_CACHE) fprintf (dump_file, "BACK visiting block %d\n", node->index);
// If the pred is entry but NOT def, then it is used before
// defined, it'll get set to []. and no need to update it.
if (pred == ENTRY_BLOCK_PTR_FOR_FN (cfun))
- continue;
+ {
+ if (DEBUG_CACHE)
+ fprintf (dump_file, "entry: bail.");
+ continue;
+ }
// Regardless of whther we have visited pred or not, if the pred has
// a non-null reference, revisit this block.
if (m_non_null.non_null_deref_p (name, pred))
- add_to_update (node);
+ {
+ if (DEBUG_CACHE)
+ fprintf (dump_file, "nonnull: update ");
+ add_to_update (node);
+ }
// If the pred block already has a range, or if it can contribute
// something new. Ie, the edge generates a range of some sort.
if (m_on_entry.get_bb_range (r, name, pred))
{
+ if (DEBUG_CACHE)
+ fprintf (dump_file, "has cache, ");
if (!r.undefined_p () || has_edge_range_p (e, name))
- add_to_update (node);
+ {
+ add_to_update (node);
+ if (DEBUG_CACHE)
+ fprintf (dump_file, "update. ");
+ }
continue;
}
- // If the pred hasn't been visited (has no range), add it to
- // the list.
+ if (DEBUG_CACHE)
+ fprintf (dump_file, "pushing undefined pred block. ");
+ // If the pred hasn't been visited (has no range), add it to the list.
gcc_checking_assert (!m_on_entry.bb_range_p (name, pred));
m_on_entry.set_bb_range (name, pred, undefined);
m_workback.quick_push (pred);
}
}
+ if (DEBUG_CACHE)
+ fprintf (dump_file, "\n");
+
+ // Now fill in the marked blocks with values.
iterative_cache_update (name);
+ if (DEBUG_CACHE)
+ fprintf (dump_file, " iterative update done.\n");
+
+ // Now that the cache has been updated, check to see if there were any
+ // SSA_NAMES used in filling the cache which were "poor values".
+ // We can evaluate them, and inject any new values into the iteration
+ // list, and see if it improves any on-entry values.
+ if (poor_list_start != m_poor_value_list.length ())
+ {
+ gcc_checking_assert (poor_list_start < m_poor_value_list.length ());
+ while (poor_list_start < m_poor_value_list.length ())
+ {
+ // Find a range for this unresolved value.
+ // Note this may spawn new cache filling cycles, but by the time it
+ // is finished, the work vectors will all be back to the same state
+ // as before the call. The update record vector will always be
+ // returned to the current state upon return.
+ struct update_record rec = m_poor_value_list.pop ();
+ basic_block calc_bb = rec.bb;
+ int_range_max tmp;
+
+ // The update work list should be empty at this point.
+ gcc_checking_assert (m_update_list.length () == 0);
+
+ if (DEBUG_CACHE)
+ {
+ fprintf (dump_file, "(%d:%d)Calculating ",
+ m_poor_value_list.length () + 1, poor_list_start);
+ print_generic_expr (dump_file, name, TDF_SLIM);
+ fprintf (dump_file, " used poor value for ");
+ print_generic_expr (dump_file, rec.calc, TDF_SLIM);
+ fprintf (dump_file, " in bb%d, trying to improve:\n",
+ calc_bb->index);
+ }
+
+ // It must have a least one edge, pick edge 0. we just want to
+ // calculate a range at the exit from the block so the caches feeding
+ // this block will be filled up.
+ gcc_checking_assert (EDGE_SUCC (calc_bb, 0));
+ query.range_on_edge (tmp, EDGE_SUCC (calc_bb, 0), rec.calc);
+
+ if (DEBUG_CACHE)
+ fprintf (dump_file, " Checking successors of bb%d :",
+ calc_bb->index);
+
+ // Try recalculating any successor blocks with the new value.
+ // Note that even if this value is refined from the initial value,
+ // it may not affect the calculation, but the iterative update
+ // will resolve that efficently.
+ FOR_EACH_EDGE (e, ei, calc_bb->succs)
+ {
+ if (DEBUG_CACHE)
+ fprintf (dump_file, "bb%d: ", e->dest->index);
+ // Only update active cache entries.
+ if (m_on_entry.bb_range_p (name, e->dest))
+ {
+ if (DEBUG_CACHE)
+ fprintf (dump_file, "update ");
+ add_to_update (e->dest);
+ }
+ }
+ if (DEBUG_CACHE)
+ fprintf (dump_file, "\n");
+ // Now see if there is a new value
+ iterative_cache_update (name);
+ }
+ }
+
}
diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h
index a1d2adf690d..6a7b4ceae3a 100644
--- a/gcc/gimple-range-cache.h
+++ b/gcc/gimple-range-cache.h
@@ -21,8 +21,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_SSA_RANGE_CACHE_H
#define GCC_SSA_RANGE_CACHE_H
-#include "gimple-range-gori.h"
-
+#include "gimple-range-gori.h"
// This global cache is used with the range engine as markers for what
// has been visited during this incarnation. Once the ranger evaluates
// a name, it is typically not re-evaluated again.
@@ -87,7 +86,7 @@ private:
class ranger_cache : public gori_compute_cache
{
public:
- ranger_cache ();
+ ranger_cache (class range_query &q);
~ranger_cache ();
virtual void ssa_range_in_bb (irange &r, tree name, basic_block bb);
@@ -104,6 +103,14 @@ private:
vec<basic_block> m_workback;
vec<basic_block> m_update_list;
+ struct update_record
+ {
+ basic_block bb; // Block which value needs to be calculated in.
+ tree calc; // SSA_NAME whch needs its value calculated
+ };
+ bool push_poor_value (basic_block bb, tree name);
+ vec<update_record> m_poor_value_list;
+ class range_query &query;
};
#endif // GCC_SSA_RANGE_CACHE_H
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index 2169b3d1e2e..b67aded30cb 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -46,7 +46,8 @@ along with GCC; see the file COPYING3. If not see
class gimple_ranger : public range_query
{
public:
- gimple_ranger (bool use_loop_info) : m_use_loop_info (use_loop_info) { }
+ gimple_ranger (bool use_loop_info) : m_cache (*this),
+ m_use_loop_info (use_loop_info) { }
virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL) OVERRIDE;
virtual bool range_of_expr (irange &r, tree name, gimple * = NULL) OVERRIDE;
virtual bool range_on_edge (irange &r, edge e, tree name) OVERRIDE;
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2020-09-19 13:34 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-19 13:34 [gcc(refs/users/aldyh/heads/ranger-staging)] Add iterative update Andrew Macleod
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).