Commit ac6f2e59 by Jan Hubicka Committed by Jan Hubicka

ipa-fnsummary.c (ipa_call_context::duplicate_from): New member function.

	* ipa-fnsummary.c (ipa_call_context::duplicate_from): New
	member function.
	(ipa_call_context::release): Add ALL parameter.
	(ipa_call_context::equal_to): New member function.
	* ipa-fnsummary.h (ipa_call_context): Add empty constructor;
	duplicate_form, release, equal_to and exists_p member functoins.
	* ipa-inline-analysis.c (node_context_cache_entry): New
	class.
	(node_context_summary): Likewise.
	(node_context_cache, node_context_cache_hit, node_context_cache_miss,
	node_context_clear): New static vars.
	(initialize_growth_caches): New function.
	(free_growth_caches): Also delete node_context_cache; output stats.
	(do_estimate_edge_time): Cache contexts.
	(reset_node_cache): New function.
	* ipa-inline.c (reset_edge_caches): Reset also node cache.
	(inline_small_functions): Initialize growth caches.
	* ipa-inline.h (reset_node_cache, initialize_growth_caches):
	Declare.
	* ipa-predicate.h (inline_param_summary::equal_to): New.
	* ipa-prop.c (ipa_agg_jf_item::equal_to): New.
	* ipa-prop.h (ipa_agg_jf_item): Declare equal_to member function.
	(ipa_agg_jump_function): Implement equal_to member function.

From-SVN: r277757
parent 360386c7
2019-11-02 Jan Hubicka <hubicka@ucw.cz> 2019-11-02 Jan Hubicka <hubicka@ucw.cz>
* ipa-fnsummary.c (ipa_call_context::duplicate_from): New
member function.
(ipa_call_context::release): Add ALL parameter.
(ipa_call_context::equal_to): New member function.
* ipa-fnsummary.h (ipa_call_context): Add empty constructor;
duplicate_form, release, equal_to and exists_p member functoins.
* ipa-inline-analysis.c (node_context_cache_entry): New
class.
(node_context_summary): Likewise.
(node_context_cache, node_context_cache_hit, node_context_cache_miss,
node_context_clear): New static vars.
(initialize_growth_caches): New function.
(free_growth_caches): Also delete node_context_cache; output stats.
(do_estimate_edge_time): Cache contexts.
(reset_node_cache): New function.
* ipa-inline.c (reset_edge_caches): Reset also node cache.
(inline_small_functions): Initialize growth caches.
* ipa-inline.h (reset_node_cache, initialize_growth_caches):
Declare.
* ipa-predicate.h (inline_param_summary::equal_to): New.
* ipa-prop.c (ipa_agg_jf_item::equal_to): New.
* ipa-prop.h (ipa_agg_jf_item): Declare equal_to member function.
(ipa_agg_jump_function): Implement equal_to member function.
2019-11-02 Jan Hubicka <hubicka@ucw.cz>
* ipa-fnsummary.c (inline_read_section): Set vector size * ipa-fnsummary.c (inline_read_section): Set vector size
ahead of time. ahead of time.
...@@ -2964,14 +2964,103 @@ ipa_call_context::ipa_call_context (cgraph_node *node, ...@@ -2964,14 +2964,103 @@ ipa_call_context::ipa_call_context (cgraph_node *node,
{ {
} }
/* Release memory used by known_vals/contexts/aggs vectors. */ void
ipa_call_context::duplicate_from (const ipa_call_context &ctx)
{
m_node = ctx.m_node;
m_possible_truths = ctx.m_possible_truths;
m_nonspec_possible_truths = ctx.m_nonspec_possible_truths;
if (ctx.m_inline_param_summary.exists ())
m_inline_param_summary = ctx.m_inline_param_summary.copy ();
else
m_inline_param_summary = vNULL;
if (ctx.m_known_vals.exists ())
m_known_vals = ctx.m_known_vals.copy ();
else
m_known_vals = vNULL;
if (ctx.m_known_contexts.exists ())
m_known_contexts = ctx.m_known_contexts.copy ();
else
m_known_contexts = vNULL;
if (ctx.m_known_aggs.exists ())
m_known_aggs = ctx.m_known_aggs.copy ();
else
m_known_aggs = vNULL;
}
/* Release memory used by known_vals/contexts/aggs vectors.
If ALL is true release also inline_param_summary.
This happens when context was previously duplciated to be stored
into cache. */
void void
ipa_call_context::release () ipa_call_context::release (bool all)
{ {
/* See if context is initialized at first place. */
if (!m_node)
return;
m_known_vals.release (); m_known_vals.release ();
m_known_contexts.release (); m_known_contexts.release ();
m_known_aggs.release (); m_known_aggs.release ();
if (all)
m_inline_param_summary.release ();
}
/* Return true if CTX describes the same call context as THIS. */
bool
ipa_call_context::equal_to (const ipa_call_context &ctx)
{
if (m_node != ctx.m_node
|| m_possible_truths != ctx.m_possible_truths
|| m_nonspec_possible_truths != ctx.m_nonspec_possible_truths)
return false;
if (m_inline_param_summary.exists () != ctx.m_inline_param_summary.exists ()
|| m_known_vals.exists () != ctx.m_known_vals.exists()
|| m_known_contexts.exists () != ctx.m_known_contexts.exists ()
|| m_known_aggs.exists () != ctx.m_known_aggs.exists ())
return false;
if (m_inline_param_summary.exists ())
{
if (m_inline_param_summary.length () != ctx.m_inline_param_summary.length ())
return false;
for (unsigned int i = 0; i < m_inline_param_summary.length (); i++)
if (!m_inline_param_summary[i].equal_to (ctx.m_inline_param_summary[i]))
return false;
}
if (m_known_vals.exists ())
{
if (m_known_vals.length () != ctx.m_known_vals.length ())
return false;
for (unsigned int i = 0; i < m_known_vals.length (); i++)
{
tree t1 = m_known_vals[i];
tree t2 = ctx.m_known_vals[i];
if (t1 != t2
&& (!t1 || !t2 || !operand_equal_p (m_known_vals[i],
ctx.m_known_vals[i], 0)))
return false;
}
}
if (m_known_contexts.exists ())
{
if (m_known_contexts.length () != ctx.m_known_contexts.length ())
return false;
for (unsigned int i = 0; i < m_known_contexts.length (); i++)
if (!m_known_contexts[i].equal_to (ctx.m_known_contexts[i]))
return false;
}
if (m_known_aggs.exists ())
{
if (m_known_aggs.length () != ctx.m_known_aggs.length ())
return false;
for (unsigned int i = 0; i < m_known_aggs.length (); i++)
if (!m_known_aggs[i]->equal_to (*ctx.m_known_aggs[i]))
return false;
}
return true;
} }
/* Estimate size and time needed to execute call in the given context. /* Estimate size and time needed to execute call in the given context.
......
...@@ -295,11 +295,21 @@ public: ...@@ -295,11 +295,21 @@ public:
vec<ipa_polymorphic_call_context> known_contexts, vec<ipa_polymorphic_call_context> known_contexts,
vec<ipa_agg_jump_function_p> known_aggs, vec<ipa_agg_jump_function_p> known_aggs,
vec<inline_param_summary> m_inline_param_summary); vec<inline_param_summary> m_inline_param_summary);
ipa_call_context ()
: m_node(NULL)
{
}
void estimate_size_and_time (int *ret_size, int *ret_min_size, void estimate_size_and_time (int *ret_size, int *ret_min_size,
sreal *ret_time, sreal *ret_time,
sreal *ret_nonspecialized_time, sreal *ret_nonspecialized_time,
ipa_hints *ret_hints); ipa_hints *ret_hints);
void release (); void duplicate_from (const ipa_call_context &ctx);
void release (bool all = false);
bool equal_to (const ipa_call_context &);
bool exists_p ()
{
return m_node != NULL;
}
private: private:
/* Called function. */ /* Called function. */
cgraph_node *m_node; cgraph_node *m_node;
......
...@@ -53,6 +53,48 @@ along with GCC; see the file COPYING3. If not see ...@@ -53,6 +53,48 @@ along with GCC; see the file COPYING3. If not see
/* Cached node/edge growths. */ /* Cached node/edge growths. */
call_summary<edge_growth_cache_entry *> *edge_growth_cache = NULL; call_summary<edge_growth_cache_entry *> *edge_growth_cache = NULL;
/* The context cache remembers estimated time/size and hints for given
ipa_call_context of a call. */
class node_context_cache_entry
{
public:
ipa_call_context ctx;
sreal time, nonspec_time;
int size;
ipa_hints hints;
node_context_cache_entry ()
: ctx ()
{
}
~node_context_cache_entry ()
{
ctx.release ();
}
};
/* At the moment we implement primitive single entry LRU cache. */
class node_context_summary
{
public:
node_context_cache_entry entry;
node_context_summary ()
: entry ()
{
}
~node_context_summary ()
{
}
};
/* Summary holding the context cache. */
static fast_function_summary <node_context_summary *, va_heap>
*node_context_cache = NULL;
/* Statistics about the context cache effectivity. */
static long node_context_cache_hit, node_context_cache_miss,
node_context_cache_clear;
/* Give initial reasons why inlining would fail on EDGE. This gets either /* Give initial reasons why inlining would fail on EDGE. This gets either
nullified or usually overwritten by more precise reasons later. */ nullified or usually overwritten by more precise reasons later. */
...@@ -77,6 +119,16 @@ initialize_inline_failed (struct cgraph_edge *e) ...@@ -77,6 +119,16 @@ initialize_inline_failed (struct cgraph_edge *e)
== CIF_FINAL_ERROR); == CIF_FINAL_ERROR);
} }
/* Allocate edge growth caches. */
void
initialize_growth_caches ()
{
edge_growth_cache
= new call_summary<edge_growth_cache_entry *> (symtab, false);
node_context_cache
= new fast_function_summary<node_context_summary *, va_heap> (symtab);
}
/* Free growth caches. */ /* Free growth caches. */
...@@ -84,7 +136,17 @@ void ...@@ -84,7 +136,17 @@ void
free_growth_caches (void) free_growth_caches (void)
{ {
delete edge_growth_cache; delete edge_growth_cache;
delete node_context_cache;
edge_growth_cache = NULL; edge_growth_cache = NULL;
node_context_cache = NULL;
if (dump_file)
fprintf (dump_file, "node context cache: %li hits, %li misses,"
" %li initializations\n",
node_context_cache_hit, node_context_cache_miss,
node_context_cache_clear);
node_context_cache_hit = 0;
node_context_cache_miss = 0;
node_context_cache_clear = 0;
} }
/* Return hints derrived from EDGE. */ /* Return hints derrived from EDGE. */
...@@ -129,7 +191,7 @@ do_estimate_edge_time (struct cgraph_edge *edge) ...@@ -129,7 +191,7 @@ do_estimate_edge_time (struct cgraph_edge *edge)
vec<ipa_polymorphic_call_context> known_contexts; vec<ipa_polymorphic_call_context> known_contexts;
vec<ipa_agg_jump_function_p> known_aggs; vec<ipa_agg_jump_function_p> known_aggs;
class ipa_call_summary *es = ipa_call_summaries->get (edge); class ipa_call_summary *es = ipa_call_summaries->get (edge);
int min_size; int min_size = -1;
callee = edge->callee->ultimate_alias_target (); callee = edge->callee->ultimate_alias_target ();
...@@ -139,8 +201,37 @@ do_estimate_edge_time (struct cgraph_edge *edge) ...@@ -139,8 +201,37 @@ do_estimate_edge_time (struct cgraph_edge *edge)
&known_contexts, &known_aggs); &known_contexts, &known_aggs);
ipa_call_context ctx (callee, clause, nonspec_clause, known_vals, ipa_call_context ctx (callee, clause, nonspec_clause, known_vals,
known_contexts, known_aggs, es->param); known_contexts, known_aggs, es->param);
ctx.estimate_size_and_time (&size, &min_size, if (node_context_cache != NULL)
&time, &nonspec_time, &hints); {
node_context_summary *e = node_context_cache->get_create (callee);
if (e->entry.ctx.equal_to (ctx))
{
node_context_cache_hit++;
size = e->entry.size;
time = e->entry.time;
nonspec_time = e->entry.nonspec_time;
hints = e->entry.hints;
}
else
{
if (e->entry.ctx.exists_p ())
node_context_cache_miss++;
else
node_context_cache_clear++;
e->entry.ctx.release (true);
e->entry.ctx = ctx;
ctx.estimate_size_and_time (&size, &min_size,
&time, &nonspec_time, &hints);
e->entry.size = size;
e->entry.time = time;
e->entry.nonspec_time = nonspec_time;
e->entry.hints = hints;
e->entry.ctx.duplicate_from (ctx);
}
}
else
ctx.estimate_size_and_time (&size, &min_size,
&time, &nonspec_time, &hints);
/* When we have profile feedback, we can quite safely identify hot /* When we have profile feedback, we can quite safely identify hot
edges and for those we disable size limits. Don't do that when edges and for those we disable size limits. Don't do that when
...@@ -160,8 +251,9 @@ do_estimate_edge_time (struct cgraph_edge *edge) ...@@ -160,8 +251,9 @@ do_estimate_edge_time (struct cgraph_edge *edge)
/* When caching, update the cache entry. */ /* When caching, update the cache entry. */
if (edge_growth_cache != NULL) if (edge_growth_cache != NULL)
{ {
ipa_fn_summaries->get (edge->callee->function_symbol ())->min_size if (min_size >= 0)
= min_size; ipa_fn_summaries->get (edge->callee->function_symbol ())->min_size
= min_size;
edge_growth_cache_entry *entry edge_growth_cache_entry *entry
= edge_growth_cache->get_create (edge); = edge_growth_cache->get_create (edge);
entry->time = time; entry->time = time;
...@@ -174,6 +266,14 @@ do_estimate_edge_time (struct cgraph_edge *edge) ...@@ -174,6 +266,14 @@ do_estimate_edge_time (struct cgraph_edge *edge)
return time; return time;
} }
/* Reset cache for NODE.
This must be done each time NODE body is modified. */
void
reset_node_cache (struct cgraph_node *node)
{
if (node_context_cache)
node_context_cache->remove (node);
}
/* Return estimated callee growth after inlining EDGE. /* Return estimated callee growth after inlining EDGE.
Only to be called via estimate_edge_size. */ Only to be called via estimate_edge_size. */
......
...@@ -1368,6 +1368,8 @@ reset_edge_caches (struct cgraph_node *node) ...@@ -1368,6 +1368,8 @@ reset_edge_caches (struct cgraph_node *node)
if (where->inlined_to) if (where->inlined_to)
where = where->inlined_to; where = where->inlined_to;
reset_node_cache (where);
if (edge_growth_cache != NULL) if (edge_growth_cache != NULL)
for (edge = where->callers; edge; edge = edge->next_caller) for (edge = where->callers; edge; edge = edge->next_caller)
if (edge->inline_failed) if (edge->inline_failed)
...@@ -1900,8 +1902,7 @@ inline_small_functions (void) ...@@ -1900,8 +1902,7 @@ inline_small_functions (void)
max_count = max_count.max (edge->count.ipa ()); max_count = max_count.max (edge->count.ipa ());
} }
ipa_free_postorder_info (); ipa_free_postorder_info ();
edge_growth_cache initialize_growth_caches ();
= new call_summary<edge_growth_cache_entry *> (symtab, false);
if (dump_file) if (dump_file)
fprintf (dump_file, fprintf (dump_file,
......
...@@ -48,6 +48,8 @@ bool growth_likely_positive (struct cgraph_node *, int); ...@@ -48,6 +48,8 @@ bool growth_likely_positive (struct cgraph_node *, int);
int do_estimate_edge_size (struct cgraph_edge *edge); int do_estimate_edge_size (struct cgraph_edge *edge);
sreal do_estimate_edge_time (struct cgraph_edge *edge); sreal do_estimate_edge_time (struct cgraph_edge *edge);
ipa_hints do_estimate_edge_hints (struct cgraph_edge *edge); ipa_hints do_estimate_edge_hints (struct cgraph_edge *edge);
void reset_node_cache (struct cgraph_node *node);
void initialize_growth_caches ();
void free_growth_caches (void); void free_growth_caches (void);
/* In ipa-inline.c */ /* In ipa-inline.c */
......
...@@ -77,6 +77,10 @@ struct inline_param_summary ...@@ -77,6 +77,10 @@ struct inline_param_summary
Value 0 is reserved for compile time invariants. */ Value 0 is reserved for compile time invariants. */
int change_prob; int change_prob;
bool equal_to (const inline_param_summary &other)
{
return change_prob == other.change_prob;
}
}; };
typedef vec<condition, va_gc> *conditions; typedef vec<condition, va_gc> *conditions;
......
...@@ -5293,4 +5293,12 @@ ipcp_transform_function (struct cgraph_node *node) ...@@ -5293,4 +5293,12 @@ ipcp_transform_function (struct cgraph_node *node)
return TODO_update_ssa_only_virtuals; return TODO_update_ssa_only_virtuals;
} }
/* Return true if OTHER describes same agg item. */
bool
ipa_agg_jf_item::equal_to (const ipa_agg_jf_item &other)
{
return offset == other.offset
&& operand_equal_p (value, other.value, 0);
}
#include "gt-ipa-prop.h" #include "gt-ipa-prop.h"
...@@ -127,6 +127,9 @@ struct GTY(()) ipa_agg_jf_item ...@@ -127,6 +127,9 @@ struct GTY(()) ipa_agg_jf_item
/* The known constant or type if this is a clobber. */ /* The known constant or type if this is a clobber. */
tree value; tree value;
/* Return true if OTHER describes same agg item. */
bool equal_to (const ipa_agg_jf_item &other);
}; };
...@@ -139,6 +142,23 @@ struct GTY(()) ipa_agg_jump_function ...@@ -139,6 +142,23 @@ struct GTY(()) ipa_agg_jump_function
vec<ipa_agg_jf_item, va_gc> *items; vec<ipa_agg_jf_item, va_gc> *items;
/* True if the data was passed by reference (as opposed to by value). */ /* True if the data was passed by reference (as opposed to by value). */
bool by_ref; bool by_ref;
/* Return true if OTHER describes same agg items. */
bool equal_to (const ipa_agg_jump_function &other)
{
if (by_ref != other.by_ref)
return false;
if (items != NULL && other.items == NULL)
return false;
if (!items)
return other.items == NULL;
if (items->length () != other.items->length ())
return false;
for (unsigned int i = 0; i < items->length (); i++)
if (!(*items)[i].equal_to ((*other.items)[i]))
return false;
return true;
}
}; };
typedef struct ipa_agg_jump_function *ipa_agg_jump_function_p; typedef struct ipa_agg_jump_function *ipa_agg_jump_function_p;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment