* [PATCH] Come up with fast {function,call}_summary classes (PR ipa/89306).
@ 2019-02-15 11:42 Martin Liška
2019-02-15 12:09 ` Martin Liška
2019-02-18 8:09 ` Jan Hubicka
0 siblings, 2 replies; 3+ messages in thread
From: Martin Liška @ 2019-02-15 11:42 UTC (permalink / raw)
To: gcc-patches; +Cc: Jan Hubicka, Martin Jambor
[-- Attachment #1: Type: text/plain, Size: 2053 bytes --]
Hi.
The patch comes up with new summaries that use vector as underlying
data structure. In order to make the code more readable I decided to
factor out some common code into base classes.
Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
I tested building Inkscape w/ LTO and Honza make the same testing
for Firefox libxul.so.
Ready to be installed?
Thanks,
Martin
gcc/ChangeLog:
2019-02-13 Martin Liska <mliska@suse.cz>
PR ipa/89306
* cgraph.c (symbol_table::create_edge): Set m_summary_id to -1
by default.
(symbol_table::free_edge): Recycle m_summary_id.
* cgraph.h (get_summary_id): New.
(symbol_table::release_symbol): Set m_summary_id to -1
by default.
(symbol_table::allocate_cgraph_symbol): Recycle m_summary_id.
* ipa-fnsummary.c (ipa_fn_summary_t): Switch from
function_summary to fast_function_summary.
* ipa-fnsummary.h (ipa_fn_summary_t): Likewise.
* ipa-pure-const.c (class funct_state_summary_t):
Switch from function_summary to fast_function_summary.
* ipa-reference.c (class ipa_ref_var_info_summary_t): Likewise.
(class ipa_ref_opt_summary_t): Switch from function_summary
to fast_function_summary.
* symbol-summary.h (class function_summary_base): New class
that is created from base of former function_summary.
(function_summary_base::unregister_hooks): New.
(class function_summary): Inherit from function_summary_base.
(class call_summary_base): New class
that is created from base of former call_summary.
(class call_summary): Inherit from call_summary_base.
(struct is_same): New.
(class fast_function_summary): New summary class.
(class fast_call_summary): New summary class.
* vec.h (vec_safe_grow_cleared): New function.
---
gcc/cgraph.c | 7 +-
gcc/cgraph.h | 44 ++-
gcc/ipa-fnsummary.c | 6 +-
gcc/ipa-fnsummary.h | 20 +-
gcc/ipa-pure-const.c | 5 +-
gcc/ipa-reference.c | 13 +-
gcc/symbol-summary.h | 840 +++++++++++++++++++++++++++++++++----------
gcc/vec.h | 11 +
8 files changed, 735 insertions(+), 211 deletions(-)
[-- Attachment #2: 0001-Come-up-with-fast-function-call-_summary-classes-PR-.patch --]
[-- Type: text/x-patch, Size: 39270 bytes --]
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index c9788d0286a..de82316d4b1 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -852,7 +852,10 @@ symbol_table::create_edge (cgraph_node *caller, cgraph_node *callee,
free_edges = NEXT_FREE_EDGE (edge);
}
else
- edge = ggc_alloc<cgraph_edge> ();
+ {
+ edge = ggc_alloc<cgraph_edge> ();
+ edge->m_summary_id = -1;
+ }
edges_count++;
@@ -1014,7 +1017,9 @@ symbol_table::free_edge (cgraph_edge *e)
ggc_free (e->indirect_info);
/* Clear out the edge so we do not dangle pointers. */
+ int summary_id = e->m_summary_id;
memset (e, 0, sizeof (*e));
+ e->m_summary_id = summary_id;
NEXT_FREE_EDGE (e) = free_edges;
free_edges = e;
edges_count--;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 2f6daa75a24..03ae411acde 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -1302,6 +1302,12 @@ public:
return m_uid;
}
+ /* Get summary id of the node. */
+ inline int get_summary_id ()
+ {
+ return m_summary_id;
+ }
+
/* Record that DECL1 and DECL2 are semantically identical function
versions. */
static void record_function_versions (tree decl1, tree decl2);
@@ -1470,6 +1476,9 @@ private:
/* Unique id of the node. */
int m_uid;
+ /* Summary id that is recycled. */
+ int m_summary_id;
+
/* Worker for call_for_symbol_and_aliases. */
bool call_for_symbol_and_aliases_1 (bool (*callback) (cgraph_node *,
void *),
@@ -1728,6 +1737,12 @@ struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
return m_uid;
}
+ /* Get summary id of the edge. */
+ inline int get_summary_id ()
+ {
+ return m_summary_id;
+ }
+
/* Rebuild cgraph edges for current function node. This needs to be run after
passes that don't update the cgraph. */
static unsigned int rebuild_edges (void);
@@ -1805,6 +1820,9 @@ private:
/* Unique id of the edge. */
int m_uid;
+ /* Summary id that is recycled. */
+ int m_summary_id;
+
/* Remove the edge from the list of the callers of the callee. */
void remove_caller (void);
@@ -2051,7 +2069,8 @@ public:
friend class cgraph_node;
friend class cgraph_edge;
- symbol_table (): cgraph_max_uid (1), edges_max_uid (1)
+ symbol_table (): cgraph_max_uid (1), cgraph_max_summary_id (0),
+ edges_max_uid (1), edges_max_summary_id (0)
{
}
@@ -2254,15 +2273,31 @@ public:
/* Dump symbol table to stderr. */
void DEBUG_FUNCTION debug (void);
+ /* Allocate new callgraph node. */
+ inline int assign_summary_id (cgraph_node *node)
+ {
+ node->m_summary_id = cgraph_max_summary_id++;
+ return node->m_summary_id;
+ }
+
+ /* Allocate new callgraph node. */
+ inline int assign_summary_id (cgraph_edge *edge)
+ {
+ edge->m_summary_id = edges_max_summary_id++;
+ return edge->m_summary_id;
+ }
+
/* Return true if assembler names NAME1 and NAME2 leads to the same symbol
name. */
static bool assembler_names_equal_p (const char *name1, const char *name2);
int cgraph_count;
int cgraph_max_uid;
+ int cgraph_max_summary_id;
int edges_count;
int edges_max_uid;
+ int edges_max_summary_id;
symtab_node* GTY(()) nodes;
asm_node* GTY(()) asmnodes;
@@ -2634,8 +2669,10 @@ symbol_table::release_symbol (cgraph_node *node)
/* Clear out the node to NULL all pointers and add the node to the free
list. */
+ int summary_id = node->m_summary_id;
memset (node, 0, sizeof (*node));
node->type = SYMTAB_FUNCTION;
+ node->m_summary_id = summary_id;
SET_NEXT_FREE_NODE (node, free_nodes);
free_nodes = node;
}
@@ -2653,7 +2690,10 @@ symbol_table::allocate_cgraph_symbol (void)
free_nodes = NEXT_FREE_NODE (node);
}
else
- node = ggc_cleared_alloc<cgraph_node> ();
+ {
+ node = ggc_cleared_alloc<cgraph_node> ();
+ node->m_summary_id = -1;
+ }
node->m_uid = cgraph_max_uid++;
return node;
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 260315da228..160261d34c9 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -85,8 +85,8 @@ along with GCC; see the file COPYING3. If not see
#include "attribs.h"
/* Summaries. */
-function_summary <ipa_fn_summary *> *ipa_fn_summaries;
-call_summary <ipa_call_summary *> *ipa_call_summaries;
+fast_function_summary <ipa_fn_summary *, va_gc> *ipa_fn_summaries;
+fast_call_summary <ipa_call_summary *, va_heap> *ipa_call_summaries;
/* Edge predicates goes here. */
static object_allocator<predicate> edge_predicate_pool ("edge predicates");
@@ -532,7 +532,7 @@ ipa_fn_summary_alloc (void)
{
gcc_checking_assert (!ipa_fn_summaries);
ipa_fn_summaries = ipa_fn_summary_t::create_ggc (symtab);
- ipa_call_summaries = new ipa_call_summary_t (symtab, false);
+ ipa_call_summaries = new ipa_call_summary_t (symtab);
}
ipa_call_summary::~ipa_call_summary ()
diff --git a/gcc/ipa-fnsummary.h b/gcc/ipa-fnsummary.h
index f1642a344d0..0f08e84ed53 100644
--- a/gcc/ipa-fnsummary.h
+++ b/gcc/ipa-fnsummary.h
@@ -173,16 +173,17 @@ struct GTY(()) ipa_fn_summary
static const int size_scale = 2;
};
-class GTY((user)) ipa_fn_summary_t: public function_summary <ipa_fn_summary *>
+class GTY((user)) ipa_fn_summary_t:
+ public fast_function_summary <ipa_fn_summary *, va_gc>
{
public:
- ipa_fn_summary_t (symbol_table *symtab, bool ggc):
- function_summary <ipa_fn_summary *> (symtab, ggc) {}
+ ipa_fn_summary_t (symbol_table *symtab):
+ fast_function_summary <ipa_fn_summary *, va_gc> (symtab) {}
static ipa_fn_summary_t *create_ggc (symbol_table *symtab)
{
struct ipa_fn_summary_t *summary = new (ggc_alloc <ipa_fn_summary_t> ())
- ipa_fn_summary_t(symtab, true);
+ ipa_fn_summary_t (symtab);
summary->disable_insertion_hook ();
return summary;
}
@@ -200,7 +201,8 @@ public:
ipa_fn_summary *src_data, ipa_fn_summary *dst_data);
};
-extern GTY(()) function_summary <ipa_fn_summary *> *ipa_fn_summaries;
+extern GTY(()) fast_function_summary <ipa_fn_summary *, va_gc>
+ *ipa_fn_summaries;
/* Information kept about callgraph edges. */
struct ipa_call_summary
@@ -236,11 +238,11 @@ struct ipa_call_summary
bool is_return_callee_uncaptured;
};
-class ipa_call_summary_t: public call_summary <ipa_call_summary *>
+class ipa_call_summary_t: public fast_call_summary <ipa_call_summary *, va_heap>
{
public:
- ipa_call_summary_t (symbol_table *symtab, bool ggc):
- call_summary <ipa_call_summary *> (symtab, ggc) {}
+ ipa_call_summary_t (symbol_table *symtab):
+ fast_call_summary <ipa_call_summary *, va_heap> (symtab) {}
/* Hook that is called by summary when an edge is duplicated. */
virtual void duplicate (cgraph_edge *src, cgraph_edge *dst,
@@ -248,7 +250,7 @@ public:
ipa_call_summary *dst_data);
};
-extern call_summary <ipa_call_summary *> *ipa_call_summaries;
+extern fast_call_summary <ipa_call_summary *, va_heap> *ipa_call_summaries;
/* In ipa-fnsummary.c */
void ipa_debug_fn_summary (struct cgraph_node *);
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index 3b3f2d8b4c5..bb561d00853 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -128,11 +128,12 @@ typedef struct funct_state_d * funct_state;
possibility that it may be desirable to move this to the cgraph
local info. */
-class funct_state_summary_t: public function_summary <funct_state_d *>
+class funct_state_summary_t:
+ public fast_function_summary <funct_state_d *, va_heap>
{
public:
funct_state_summary_t (symbol_table *symtab):
- function_summary <funct_state_d *> (symtab) {}
+ fast_function_summary <funct_state_d *, va_heap> (symtab) {}
virtual void insert (cgraph_node *, funct_state_d *state);
virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node,
diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c
index d1759a374bc..9ef03c2505b 100644
--- a/gcc/ipa-reference.c
+++ b/gcc/ipa-reference.c
@@ -110,23 +110,22 @@ static bitmap_obstack local_info_obstack;
/* Obstack holding global analysis live forever. */
static bitmap_obstack optimization_summary_obstack;
-class ipa_ref_var_info_summary_t: public function_summary
- <ipa_reference_vars_info_d *>
+class ipa_ref_var_info_summary_t: public fast_function_summary
+ <ipa_reference_vars_info_d *, va_heap>
{
public:
ipa_ref_var_info_summary_t (symbol_table *symtab):
- function_summary <ipa_reference_vars_info_d *> (symtab) {}
+ fast_function_summary <ipa_reference_vars_info_d *, va_heap> (symtab) {}
};
static ipa_ref_var_info_summary_t *ipa_ref_var_info_summaries = NULL;
-class ipa_ref_opt_summary_t: public function_summary
- <ipa_reference_optimization_summary_d *>
+class ipa_ref_opt_summary_t: public fast_function_summary
+ <ipa_reference_optimization_summary_d *, va_heap>
{
public:
ipa_ref_opt_summary_t (symbol_table *symtab):
- function_summary <ipa_reference_optimization_summary_d *> (symtab) {}
-
+ fast_function_summary <ipa_reference_optimization_summary_d *, va_heap> (symtab) {}
virtual void remove (cgraph_node *src_node,
ipa_reference_optimization_summary_d *data);
diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h
index f2378cdd749..0219f3a81ea 100644
--- a/gcc/symbol-summary.h
+++ b/gcc/symbol-summary.h
@@ -21,6 +21,90 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_SYMBOL_SUMMARY_H
#define GCC_SYMBOL_SUMMARY_H
+/* Base class for function_summary and fast_function_summary classes. */
+
+template <class T>
+class function_summary_base
+{
+public:
+ /* Default construction takes SYMTAB as an argument. */
+ function_summary_base (symbol_table *symtab): m_symtab (symtab),
+ m_insertion_enabled (true), m_released (false)
+ {}
+
+ /* Basic implementation of insert operation. */
+ virtual void insert (cgraph_node *, T *) {}
+
+ /* Basic implementation of removal operation. */
+ virtual void remove (cgraph_node *, T *) {}
+
+ /* Basic implementation of duplication operation. */
+ virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *) {}
+
+ /* Enable insertion hook invocation. */
+ void enable_insertion_hook ()
+ {
+ m_insertion_enabled = true;
+ }
+
+ /* Enable insertion hook invocation. */
+ void disable_insertion_hook ()
+ {
+ m_insertion_enabled = false;
+ }
+
+protected:
+ /* Allocates new data that are stored within map. */
+ T* allocate_new ()
+ {
+ /* Call gcc_internal_because we do not want to call finalizer for
+ a type T. We call dtor explicitly. */
+ return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
+ }
+
+ /* Release an item that is stored within map. */
+ void release (T *item)
+ {
+ if (is_ggc ())
+ {
+ item->~T ();
+ ggc_free (item);
+ }
+ else
+ delete item;
+ }
+
+ /* Unregister all call-graph hooks. */
+ void unregister_hooks ();
+
+ /* Internal summary insertion hook pointer. */
+ cgraph_node_hook_list *m_symtab_insertion_hook;
+ /* Internal summary removal hook pointer. */
+ cgraph_node_hook_list *m_symtab_removal_hook;
+ /* Internal summary duplication hook pointer. */
+ cgraph_2node_hook_list *m_symtab_duplication_hook;
+ /* Symbol table the summary is registered to. */
+ symbol_table *m_symtab;
+
+ /* Indicates if insertion hook is enabled. */
+ bool m_insertion_enabled;
+ /* Indicates if the summary is released. */
+ bool m_released;
+
+private:
+ /* Return true when the summary uses GGC memory for allocation. */
+ virtual bool is_ggc () = 0;
+};
+
+template <typename T>
+void
+function_summary_base<T>::unregister_hooks ()
+{
+ m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook);
+ m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook);
+ m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook);
+}
+
/* We want to pass just pointer types as argument for function_summary
template class. */
@@ -43,7 +127,7 @@ private:
a memory gained by garbage collected memory. */
template <class T>
-class GTY((user)) function_summary <T *>
+class GTY((user)) function_summary <T *>: public function_summary_base<T>
{
public:
/* Default construction takes SYMTAB as an argument. */
@@ -55,7 +139,8 @@ public:
release ();
}
- /* Destruction method that can be called for GGT purpose. */
+ /* Destruction method that can be called for GGC purpose. */
+ using function_summary_base<T>::release;
void release ();
/* Traverses all summarys with a function F called with
@@ -66,26 +151,6 @@ public:
m_map.traverse <f> (a);
}
- /* Basic implementation of insert operation. */
- virtual void insert (cgraph_node *, T *) {}
-
- /* Basic implementation of removal operation. */
- virtual void remove (cgraph_node *, T *) {}
-
- /* Basic implementation of duplication operation. */
- virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *) {}
-
- /* Allocates new data that are stored within map. */
- T* allocate_new ()
- {
- /* Call gcc_internal_because we do not want to call finalizer for
- a type T. We call dtor explicitly. */
- return m_ggc ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
- }
-
- /* Release an item that is stored within map. */
- void release (T *item);
-
/* Getter for summary callgraph node pointer. If a summary for a node
does not exist it will be created. */
T* get_create (cgraph_node *node)
@@ -93,7 +158,7 @@ public:
bool existed;
T **v = &m_map.get_or_insert (node->get_uid (), &existed);
if (!existed)
- *v = allocate_new ();
+ *v = this->allocate_new ();
return *v;
}
@@ -106,6 +171,7 @@ public:
}
/* Remove node from summary. */
+ using function_summary_base<T>::remove;
void remove (cgraph_node *node)
{
int uid = node->get_uid ();
@@ -113,34 +179,16 @@ public:
if (v)
{
m_map.remove (uid);
- release (*v);
+ this->release (*v);
}
}
- /* Return number of elements handled by data structure. */
- size_t elements ()
- {
- return m_map.elements ();
- }
-
/* Return true if a summary for the given NODE already exists. */
bool exists (cgraph_node *node)
{
return m_map.get (node->get_uid ()) != NULL;
}
- /* Enable insertion hook invocation. */
- void enable_insertion_hook ()
- {
- m_insertion_enabled = true;
- }
-
- /* Enable insertion hook invocation. */
- void disable_insertion_hook ()
- {
- m_insertion_enabled = false;
- }
-
/* Symbol insertion hook that is registered to symbol table. */
static void symtab_insertion (cgraph_node *node, void *data);
@@ -156,22 +204,16 @@ protected:
bool m_ggc;
private:
+ /* Indication if we use ggc summary. */
+ virtual bool is_ggc ()
+ {
+ return m_ggc;
+ }
+
typedef int_hash <int, 0, -1> map_hash;
- /* Indicates if insertion hook is enabled. */
- bool m_insertion_enabled;
- /* Indicates if the summary is released. */
- bool m_released;
/* Main summary store, where summary ID is used as key. */
hash_map <map_hash, T *> m_map;
- /* Internal summary insertion hook pointer. */
- cgraph_node_hook_list *m_symtab_insertion_hook;
- /* Internal summary removal hook pointer. */
- cgraph_node_hook_list *m_symtab_removal_hook;
- /* Internal summary duplication hook pointer. */
- cgraph_2node_hook_list *m_symtab_duplication_hook;
- /* Symbol table the summary is registered to. */
- symbol_table *m_symtab;
template <typename U> friend void gt_ggc_mx (function_summary <U *> * const &);
template <typename U> friend void gt_pch_nx (function_summary <U *> * const &);
@@ -181,50 +223,34 @@ private:
template <typename T>
function_summary<T *>::function_summary (symbol_table *symtab, bool ggc):
- m_ggc (ggc), m_insertion_enabled (true), m_released (false), m_map (13, ggc),
- m_symtab (symtab)
+ function_summary_base<T> (symtab), m_ggc (ggc), m_map (13, ggc)
{
- m_symtab_insertion_hook
- = symtab->add_cgraph_insertion_hook (function_summary::symtab_insertion,
- this);
-
- m_symtab_removal_hook
- = symtab->add_cgraph_removal_hook (function_summary::symtab_removal, this);
- m_symtab_duplication_hook
- = symtab->add_cgraph_duplication_hook (function_summary::symtab_duplication,
- this);
+ this->m_symtab_insertion_hook
+ = this->m_symtab->add_cgraph_insertion_hook (function_summary::symtab_insertion,
+ this);
+ this->m_symtab_removal_hook
+ = this->m_symtab->add_cgraph_removal_hook (function_summary::symtab_removal,
+ this);
+ this->m_symtab_duplication_hook
+ = this->m_symtab->add_cgraph_duplication_hook (function_summary::symtab_duplication,
+ this);
}
template <typename T>
void
function_summary<T *>::release ()
{
- if (m_released)
+ if (this->m_released)
return;
- m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook);
- m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook);
- m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook);
+ this->unregister_hooks ();
/* Release all summaries. */
typedef typename hash_map <map_hash, T *>::iterator map_iterator;
for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
- release ((*it).second);
+ this->release ((*it).second);
- m_released = true;
-}
-
-template <typename T>
-void
-function_summary<T *>::release (T *item)
-{
- if (m_ggc)
- {
- item->~T ();
- ggc_free (item);
- }
- else
- delete item;
+ this->m_released = true;
}
template <typename T>
@@ -244,19 +270,7 @@ function_summary<T *>::symtab_removal (cgraph_node *node, void *data)
{
gcc_checking_assert (node->get_uid ());
function_summary *summary = (function_summary <T *> *) (data);
-
- int uid = node->get_uid ();
- T **v = summary->m_map.get (uid);
-
- if (v)
- {
- summary->remove (node, *v);
-
- if (!summary->m_ggc)
- delete (*v);
-
- summary->m_map.remove (uid);
- }
+ summary->remove (node);
}
template <typename T>
@@ -268,12 +282,7 @@ function_summary<T *>::symtab_duplication (cgraph_node *node,
T *v = summary->get (node);
if (v)
- {
- /* This load is necessary, because we insert a new value! */
- T *duplicate = summary->allocate_new ();
- summary->m_map.put (node2->get_uid (), duplicate);
- summary->duplicate (node, node2, v, duplicate);
- }
+ summary->duplicate (node, node2, v, summary->get_create (node2));
}
template <typename T>
@@ -301,42 +310,49 @@ gt_pch_nx(function_summary<T *>* const& summary, gt_pointer_operator op,
gt_pch_nx (&summary->m_map, op, cookie);
}
-/* An impossible class templated by non-pointers so, which makes sure that only
- summaries gathering pointers can be created. */
+/* Help template from std c++11. */
-template <class T>
-class call_summary
+template<typename T, typename U>
+struct is_same
+{
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T,T> //specialization
+{
+ static const bool value = true;
+};
+
+/* We want to pass just pointer types as argument for fast_function_summary
+ template class. */
+
+template <class T, class V>
+class fast_function_summary
{
private:
- call_summary();
+ fast_function_summary ();
};
-/* Class to store auxiliary information about call graph edges. */
+/* Function vector summary is a fast implementation of function_summary that
+ utilizes vector as primary storage of summaries. */
-template <class T>
-class GTY((user)) call_summary <T *>
+template <class T, class V>
+class GTY((user)) fast_function_summary <T *, V>
+ : public function_summary_base<T>
{
public:
/* Default construction takes SYMTAB as an argument. */
- call_summary (symbol_table *symtab, bool ggc = false): m_ggc (ggc),
- m_initialize_when_cloning (false), m_map (13, ggc), m_released (false),
- m_symtab (symtab)
- {
- m_symtab_removal_hook =
- symtab->add_edge_removal_hook
- (call_summary::symtab_removal, this);
- m_symtab_duplication_hook =
- symtab->add_edge_duplication_hook
- (call_summary::symtab_duplication, this);
- }
+ fast_function_summary (symbol_table *symtab);
/* Destructor. */
- virtual ~call_summary ()
+ virtual ~fast_function_summary ()
{
release ();
}
- /* Destruction method that can be called for GGT purpose. */
+ /* Destruction method that can be called for GGC purpose. */
+ using function_summary_base<T>::release;
void release ();
/* Traverses all summarys with a function F called with
@@ -344,25 +360,309 @@ public:
template<typename Arg, bool (*f)(const T &, Arg)>
void traverse (Arg a) const
{
- m_map.traverse <f> (a);
+ for (unsigned i = 0; i < m_vector->length (); i++)
+ if ((*m_vector[i]) != NULL)
+ f ((*m_vector)[i]);
+ }
+
+ /* Getter for summary callgraph node pointer. If a summary for a node
+ does not exist it will be created. */
+ T* get_create (cgraph_node *node)
+ {
+ int id = node->get_summary_id ();
+ if (id == -1)
+ id = this->m_symtab->assign_summary_id (node);
+
+ if ((unsigned int)id >= m_vector->length ())
+ vec_safe_grow_cleared (m_vector,
+ this->m_symtab->cgraph_max_summary_id);
+
+ if ((*m_vector)[id] == NULL)
+ (*m_vector)[id] = this->allocate_new ();
+
+ return (*m_vector)[id];
+ }
+
+ /* Getter for summary callgraph node pointer. */
+ T* get (cgraph_node *node) ATTRIBUTE_PURE
+ {
+ return exists (node) ? (*m_vector)[node->get_summary_id ()] : NULL;
}
+ using function_summary_base<T>::remove;
+ void remove (cgraph_node *node)
+ {
+ if (exists (node))
+ {
+ int id = node->get_summary_id ();
+ this->release ((*m_vector)[id]);
+ (*m_vector)[id] = NULL;
+ }
+ }
+
+ /* Return true if a summary for the given NODE already exists. */
+ bool exists (cgraph_node *node)
+ {
+ int id = node->get_summary_id ();
+ return (id != -1
+ && (unsigned int)id < m_vector->length ()
+ && (*m_vector)[id] != NULL);
+ }
+
+ /* Symbol insertion hook that is registered to symbol table. */
+ static void symtab_insertion (cgraph_node *node, void *data);
+
+ /* Symbol removal hook that is registered to symbol table. */
+ static void symtab_removal (cgraph_node *node, void *data);
+
+ /* Symbol duplication hook that is registered to symbol table. */
+ static void symtab_duplication (cgraph_node *node, cgraph_node *node2,
+ void *data);
+
+private:
+ virtual bool is_ggc ();
+
+ /* Summary is stored in the vector. */
+ vec <T *, V> *m_vector;
+
+ template <typename U> friend void gt_ggc_mx (fast_function_summary <U *, va_gc> * const &);
+ template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &);
+ template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &,
+ gt_pointer_operator, void *);
+};
+
+template <typename T, typename V>
+fast_function_summary<T *, V>::fast_function_summary (symbol_table *symtab):
+ function_summary_base<T> (symtab), m_vector (NULL)
+{
+ vec_alloc (m_vector, 13);
+ this->m_symtab_insertion_hook
+ = this->m_symtab->add_cgraph_insertion_hook (fast_function_summary::symtab_insertion,
+ this);
+ this->m_symtab_removal_hook
+ = this->m_symtab->add_cgraph_removal_hook (fast_function_summary::symtab_removal,
+ this);
+ this->m_symtab_duplication_hook
+ = this->m_symtab->add_cgraph_duplication_hook (fast_function_summary::symtab_duplication,
+ this);
+}
+
+template <typename T, typename V>
+void
+fast_function_summary<T *, V>::release ()
+{
+ if (this->m_released)
+ return;
+
+ this->unregister_hooks ();
+
+ /* Release all summaries. */
+ for (unsigned i = 0; i < m_vector->length (); i++)
+ if ((*m_vector)[i] != NULL)
+ this->release ((*m_vector)[i]);
+
+ this->m_released = true;
+}
+
+template <typename T, typename V>
+void
+fast_function_summary<T *, V>::symtab_insertion (cgraph_node *node, void *data)
+{
+ gcc_checking_assert (node->get_uid ());
+ fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
+
+ if (summary->m_insertion_enabled)
+ summary->insert (node, summary->get_create (node));
+}
+
+template <typename T, typename V>
+void
+fast_function_summary<T *, V>::symtab_removal (cgraph_node *node, void *data)
+{
+ gcc_checking_assert (node->get_uid ());
+ fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
+
+ if (summary->exists (node))
+ summary->remove (node);
+}
+
+template <typename T, typename V>
+void
+fast_function_summary<T *, V>::symtab_duplication (cgraph_node *node,
+ cgraph_node *node2,
+ void *data)
+{
+ fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
+ T *v = summary->get (node);
+
+ if (v)
+ {
+ T *duplicate = summary->get_create (node2);
+ summary->duplicate (node, node2, v, duplicate);
+ }
+}
+
+template <typename T, typename V>
+inline bool
+fast_function_summary<T *, V>::is_ggc ()
+{
+ return is_same<V, va_gc>::value;
+}
+
+template <typename T>
+void
+gt_ggc_mx (fast_function_summary<T *, va_heap>* const &)
+{
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_function_summary<T *, va_heap>* const &)
+{
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_function_summary<T *, va_heap>* const&, gt_pointer_operator,
+ void *)
+{
+}
+
+template <typename T>
+void
+gt_ggc_mx (fast_function_summary<T *, va_gc>* const &summary)
+{
+ ggc_test_and_set_mark (summary->m_vector);
+ gt_ggc_mx (summary->m_vector);
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_function_summary<T *, va_gc>* const &summary)
+{
+ gt_pch_nx (summary->m_vector);
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_function_summary<T *, va_gc>* const& summary,
+ gt_pointer_operator op,
+ void *cookie)
+{
+ gt_pch_nx (summary->m_vector, op, cookie);
+}
+
+/* Base class for call_summary and fast_call_summary classes. */
+
+template <class T>
+class call_summary_base
+{
+public:
+ /* Default construction takes SYMTAB as an argument. */
+ call_summary_base (symbol_table *symtab): m_symtab (symtab),
+ m_initialize_when_cloning (true), m_released (false)
+ {}
+
/* Basic implementation of removal operation. */
virtual void remove (cgraph_edge *, T *) {}
/* Basic implementation of duplication operation. */
virtual void duplicate (cgraph_edge *, cgraph_edge *, T *, T *) {}
+protected:
/* Allocates new data that are stored within map. */
T* allocate_new ()
{
/* Call gcc_internal_because we do not want to call finalizer for
a type T. We call dtor explicitly. */
- return m_ggc ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
+ return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
}
/* Release an item that is stored within map. */
- void release (T *item);
+ void release (T *item)
+ {
+ if (is_ggc ())
+ {
+ item->~T ();
+ ggc_free (item);
+ }
+ else
+ delete item;
+ }
+
+ /* Unregister all call-graph hooks. */
+ void unregister_hooks ();
+
+ /* Symbol table the summary is registered to. */
+ symbol_table *m_symtab;
+
+ /* Internal summary removal hook pointer. */
+ cgraph_edge_hook_list *m_symtab_removal_hook;
+ /* Internal summary duplication hook pointer. */
+ cgraph_2edge_hook_list *m_symtab_duplication_hook;
+ /* Initialize summary for an edge that is cloned. */
+ bool m_initialize_when_cloning;
+ /* Indicates if the summary is released. */
+ bool m_released;
+
+private:
+ /* Return true when the summary uses GGC memory for allocation. */
+ virtual bool is_ggc () = 0;
+};
+
+template <typename T>
+void
+call_summary_base<T>::unregister_hooks ()
+{
+ m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
+ m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
+}
+
+/* An impossible class templated by non-pointers so, which makes sure that only
+ summaries gathering pointers can be created. */
+
+template <class T>
+class call_summary
+{
+private:
+ call_summary ();
+};
+
+/* Class to store auxiliary information about call graph edges. */
+
+template <class T>
+class GTY((user)) call_summary <T *>: public call_summary_base<T>
+{
+public:
+ /* Default construction takes SYMTAB as an argument. */
+ call_summary (symbol_table *symtab, bool ggc = false)
+ : call_summary_base<T> (symtab), m_ggc (ggc), m_map (13, ggc)
+ {
+ this->m_symtab_removal_hook
+ = this->m_symtab->add_edge_removal_hook (call_summary::symtab_removal,
+ this);
+ this->m_symtab_duplication_hook
+ = this->m_symtab->add_edge_duplication_hook (call_summary::symtab_duplication,
+ this);
+ }
+
+ /* Destructor. */
+ virtual ~call_summary ()
+ {
+ release ();
+ }
+
+ /* Destruction method that can be called for GGC purpose. */
+ using call_summary_base<T>::release;
+ void release ();
+
+ /* Traverses all summarys with an edge E called with
+ ARG as argument. */
+ template<typename Arg, bool (*f)(const T &, Arg)>
+ void traverse (Arg a) const
+ {
+ m_map.traverse <f> (a);
+ }
/* Getter for summary callgraph edge pointer.
If a summary for an edge does not exist, it will be created. */
@@ -371,7 +671,7 @@ public:
bool existed;
T **v = &m_map.get_or_insert (edge->get_uid (), &existed);
if (!existed)
- *v = allocate_new ();
+ *v = this->allocate_new ();
return *v;
}
@@ -384,6 +684,7 @@ public:
}
/* Remove edge from summary. */
+ using call_summary_base<T>::remove;
void remove (cgraph_edge *edge)
{
int uid = edge->get_uid ();
@@ -391,16 +692,10 @@ public:
if (v)
{
m_map.remove (uid);
- release (*v);
+ this->release (*v);
}
}
- /* Return number of elements handled by data structure. */
- size_t elements ()
- {
- return m_map.elements ();
- }
-
/* Return true if a summary for the given EDGE already exists. */
bool exists (cgraph_edge *edge)
{
@@ -418,22 +713,17 @@ protected:
/* Indication if we use ggc summary. */
bool m_ggc;
- /* Initialize summary for an edge that is cloned. */
- bool m_initialize_when_cloning;
-
private:
+ /* Indication if we use ggc summary. */
+ virtual bool is_ggc ()
+ {
+ return m_ggc;
+ }
+
typedef int_hash <int, 0, -1> map_hash;
/* Main summary store, where summary ID is used as key. */
hash_map <map_hash, T *> m_map;
- /* Internal summary removal hook pointer. */
- cgraph_edge_hook_list *m_symtab_removal_hook;
- /* Internal summary duplication hook pointer. */
- cgraph_2edge_hook_list *m_symtab_duplication_hook;
- /* Indicates if the summary is released. */
- bool m_released;
- /* Symbol table the summary is registered to. */
- symbol_table *m_symtab;
template <typename U> friend void gt_ggc_mx (call_summary <U *> * const &);
template <typename U> friend void gt_pch_nx (call_summary <U *> * const &);
@@ -445,31 +735,17 @@ template <typename T>
void
call_summary<T *>::release ()
{
- if (m_released)
+ if (this->m_released)
return;
- m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
- m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
+ this->unregister_hooks ();
/* Release all summaries. */
typedef typename hash_map <map_hash, T *>::iterator map_iterator;
for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
- release ((*it).second);
+ this->release ((*it).second);
- m_released = true;
-}
-
-template <typename T>
-void
-call_summary<T *>::release (T *item)
-{
- if (m_ggc)
- {
- item->~T ();
- ggc_free (item);
- }
- else
- delete item;
+ this->m_released = true;
}
template <typename T>
@@ -477,16 +753,7 @@ void
call_summary<T *>::symtab_removal (cgraph_edge *edge, void *data)
{
call_summary *summary = (call_summary <T *> *) (data);
-
- int h_uid = edge->get_uid ();
- T **v = summary->m_map.get (h_uid);
-
- if (v)
- {
- summary->remove (edge, *v);
- summary->release (*v);
- summary->m_map.remove (h_uid);
- }
+ summary->remove (edge);
}
template <typename T>
@@ -500,21 +767,11 @@ call_summary<T *>::symtab_duplication (cgraph_edge *edge1,
if (summary->m_initialize_when_cloning)
edge1_summary = summary->get_create (edge1);
else
- {
- T **v = summary->m_map.get (edge1->get_uid ());
- if (v)
- {
- /* This load is necessary, because we insert a new value! */
- edge1_summary = *v;
- }
- }
+ edge1_summary = summary->get (edge1);
if (edge1_summary)
- {
- T *duplicate = summary->allocate_new ();
- summary->m_map.put (edge2->get_uid (), duplicate);
- summary->duplicate (edge1, edge2, edge1_summary, duplicate);
- }
+ summary->duplicate (edge1, edge2, edge1_summary,
+ summary->get_create (edge2));
}
template <typename T>
@@ -542,4 +799,213 @@ gt_pch_nx(call_summary<T *>* const& summary, gt_pointer_operator op,
gt_pch_nx (&summary->m_map, op, cookie);
}
+/* We want to pass just pointer types as argument for fast_call_summary
+ template class. */
+
+template <class T, class V>
+class fast_call_summary
+{
+private:
+ fast_call_summary ();
+};
+
+/* Call vector summary is a fast implementation of call_summary that
+ utilizes vector as primary storage of summaries. */
+
+template <class T, class V>
+class GTY((user)) fast_call_summary <T *, V>: public call_summary_base<T>
+{
+public:
+ /* Default construction takes SYMTAB as an argument. */
+ fast_call_summary (symbol_table *symtab)
+ : call_summary_base<T> (symtab), m_vector (NULL)
+ {
+ vec_alloc (m_vector, 13);
+ this->m_symtab_removal_hook
+ = this->m_symtab->add_edge_removal_hook (fast_call_summary::symtab_removal,
+ this);
+ this->m_symtab_duplication_hook
+ = this->m_symtab->add_edge_duplication_hook (fast_call_summary::symtab_duplication,
+ this);
+ }
+
+ /* Destructor. */
+ virtual ~fast_call_summary ()
+ {
+ release ();
+ }
+
+ /* Destruction method that can be called for GGC purpose. */
+ using call_summary_base<T>::release;
+ void release ();
+
+ /* Traverses all summarys with an edge F called with
+ ARG as argument. */
+ template<typename Arg, bool (*f)(const T &, Arg)>
+ void traverse (Arg a) const
+ {
+ for (unsigned i = 0; i < m_vector->length (); i++)
+ if ((*m_vector[i]) != NULL)
+ f ((*m_vector)[i]);
+ }
+
+ /* Getter for summary callgraph edge pointer.
+ If a summary for an edge does not exist, it will be created. */
+ T* get_create (cgraph_edge *edge)
+ {
+ int id = edge->get_summary_id ();
+ if (id == -1)
+ id = this->m_symtab->assign_summary_id (edge);
+
+ if ((unsigned)id >= m_vector->length ())
+ vec_safe_grow_cleared (m_vector, this->m_symtab->edges_max_summary_id);
+
+ if ((*m_vector)[id] == NULL)
+ (*m_vector)[id] = this->allocate_new ();
+
+ return (*m_vector)[id];
+ }
+
+ /* Getter for summary callgraph edge pointer. */
+ T* get (cgraph_edge *edge) ATTRIBUTE_PURE
+ {
+ return exists (edge) ? (*m_vector)[edge->get_summary_id ()] : NULL;
+ }
+
+ /* Remove edge from summary. */
+ using call_summary_base<T>::remove;
+ void remove (cgraph_edge *edge)
+ {
+ if (exists (edge))
+ {
+ int id = edge->get_summary_id ();
+ this->release ((*m_vector)[id]);
+ (*m_vector)[id] = NULL;
+ }
+ }
+
+ /* Return true if a summary for the given EDGE already exists. */
+ bool exists (cgraph_edge *edge)
+ {
+ int id = edge->get_summary_id ();
+ return (id != -1
+ && (unsigned)id < m_vector->length ()
+ && (*m_vector)[id] != NULL);
+ }
+
+ /* Symbol removal hook that is registered to symbol table. */
+ static void symtab_removal (cgraph_edge *edge, void *data);
+
+ /* Symbol duplication hook that is registered to symbol table. */
+ static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2,
+ void *data);
+
+private:
+ virtual bool is_ggc ();
+
+ /* Summary is stored in the vector. */
+ vec <T *, V> *m_vector;
+
+ template <typename U> friend void gt_ggc_mx (fast_call_summary <U *, va_gc> * const &);
+ template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &);
+ template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &,
+ gt_pointer_operator, void *);
+};
+
+template <typename T, typename V>
+void
+fast_call_summary<T *, V>::release ()
+{
+ if (this->m_released)
+ return;
+
+ this->unregister_hooks ();
+
+ /* Release all summaries. */
+ for (unsigned i = 0; i < m_vector->length (); i++)
+ if ((*m_vector)[i] != NULL)
+ this->release ((*m_vector)[i]);
+
+ this->m_released = true;
+}
+
+template <typename T, typename V>
+void
+fast_call_summary<T *, V>::symtab_removal (cgraph_edge *edge, void *data)
+{
+ fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
+ summary->remove (edge);
+}
+
+template <typename T, typename V>
+void
+fast_call_summary<T *, V>::symtab_duplication (cgraph_edge *edge1,
+ cgraph_edge *edge2, void *data)
+{
+ fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
+ T *edge1_summary = NULL;
+
+ if (summary->m_initialize_when_cloning)
+ edge1_summary = summary->get_create (edge1);
+ else
+ edge1_summary = summary->get (edge1);
+
+ if (edge1_summary)
+ {
+ T *duplicate = summary->get_create (edge2);
+ summary->duplicate (edge1, edge2, edge1_summary, duplicate);
+ }
+}
+
+template <typename T, typename V>
+inline bool
+fast_call_summary<T *, V>::is_ggc ()
+{
+ return is_same<V, va_gc>::value;
+}
+
+template <typename T>
+void
+gt_ggc_mx (fast_call_summary<T *, va_heap>* const &summary)
+{
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_call_summary<T *, va_heap>* const &summary)
+{
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_call_summary<T *, va_heap>* const& summary,
+ gt_pointer_operator op,
+ void *cookie)
+{
+}
+
+template <typename T>
+void
+gt_ggc_mx (fast_call_summary<T *, va_gc>* const &summary)
+{
+ ggc_test_and_set_mark (summary->m_vector);
+ gt_ggc_mx (&summary->m_vector);
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_call_summary<T *, va_gc>* const &summary)
+{
+ gt_pch_nx (&summary->m_vector);
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_call_summary<T *, va_gc>* const& summary,
+ gt_pointer_operator op,
+ void *cookie)
+{
+ gt_pch_nx (&summary->m_vector, op, cookie);
+}
+
#endif /* GCC_SYMBOL_SUMMARY_H */
diff --git a/gcc/vec.h b/gcc/vec.h
index 8c2a39b0b05..4bd9df9aba5 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -732,6 +732,17 @@ vec_safe_grow_cleared (vec<T, A, vl_embed> *&v, unsigned len CXX_MEM_STAT_INFO)
}
+/* Assume V is not NULL. */
+
+template<typename T>
+inline void
+vec_safe_grow_cleared (vec<T, va_heap, vl_ptr> *&v,
+ unsigned len CXX_MEM_STAT_INFO)
+{
+ v->safe_grow_cleared (len);
+}
+
+
/* If V is NULL return false, otherwise return V->iterate(IX, PTR). */
template<typename T, typename A>
inline bool
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Come up with fast {function,call}_summary classes (PR ipa/89306).
2019-02-15 11:42 [PATCH] Come up with fast {function,call}_summary classes (PR ipa/89306) Martin Liška
@ 2019-02-15 12:09 ` Martin Liška
2019-02-18 8:09 ` Jan Hubicka
1 sibling, 0 replies; 3+ messages in thread
From: Martin Liška @ 2019-02-15 12:09 UTC (permalink / raw)
To: gcc-patches; +Cc: Jan Hubicka, Martin Jambor
[-- Attachment #1: Type: text/plain, Size: 60 bytes --]
Updated version where I fixed one function comment.
Martin
[-- Attachment #2: 0001-Come-up-with-fast-function-call-_summary-classes-PR-.patch --]
[-- Type: text/x-patch, Size: 41205 bytes --]
From fb1cf6f220d6af2c1676e58bd36b160fa8d9706b Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Mon, 11 Feb 2019 14:58:31 +0100
Subject: [PATCH] Come up with fast {function,call}_summary classes (PR
ipa/89306).
gcc/ChangeLog:
2019-02-13 Martin Liska <mliska@suse.cz>
PR ipa/89306
* cgraph.c (symbol_table::create_edge): Set m_summary_id to -1
by default.
(symbol_table::free_edge): Recycle m_summary_id.
* cgraph.h (get_summary_id): New.
(symbol_table::release_symbol): Set m_summary_id to -1
by default.
(symbol_table::allocate_cgraph_symbol): Recycle m_summary_id.
* ipa-fnsummary.c (ipa_fn_summary_t): Switch from
function_summary to fast_function_summary.
* ipa-fnsummary.h (ipa_fn_summary_t): Likewise.
* ipa-pure-const.c (class funct_state_summary_t):
Switch from function_summary to fast_function_summary.
* ipa-reference.c (class ipa_ref_var_info_summary_t): Likewise.
(class ipa_ref_opt_summary_t): Switch from function_summary
to fast_function_summary.
* symbol-summary.h (class function_summary_base): New class
that is created from base of former function_summary.
(function_summary_base::unregister_hooks): New.
(class function_summary): Inherit from function_summary_base.
(class call_summary_base): New class
that is created from base of former call_summary.
(class call_summary): Inherit from call_summary_base.
(struct is_same): New.
(class fast_function_summary): New summary class.
(class fast_call_summary): New summary class.
* vec.h (vec_safe_grow_cleared): New function.
---
gcc/cgraph.c | 7 +-
gcc/cgraph.h | 44 ++-
gcc/ipa-fnsummary.c | 6 +-
gcc/ipa-fnsummary.h | 20 +-
gcc/ipa-pure-const.c | 5 +-
gcc/ipa-reference.c | 13 +-
gcc/symbol-summary.h | 840 +++++++++++++++++++++++++++++++++----------
gcc/vec.h | 11 +
8 files changed, 735 insertions(+), 211 deletions(-)
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index c9788d0286a..de82316d4b1 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -852,7 +852,10 @@ symbol_table::create_edge (cgraph_node *caller, cgraph_node *callee,
free_edges = NEXT_FREE_EDGE (edge);
}
else
- edge = ggc_alloc<cgraph_edge> ();
+ {
+ edge = ggc_alloc<cgraph_edge> ();
+ edge->m_summary_id = -1;
+ }
edges_count++;
@@ -1014,7 +1017,9 @@ symbol_table::free_edge (cgraph_edge *e)
ggc_free (e->indirect_info);
/* Clear out the edge so we do not dangle pointers. */
+ int summary_id = e->m_summary_id;
memset (e, 0, sizeof (*e));
+ e->m_summary_id = summary_id;
NEXT_FREE_EDGE (e) = free_edges;
free_edges = e;
edges_count--;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 2f6daa75a24..c294602d762 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -1302,6 +1302,12 @@ public:
return m_uid;
}
+ /* Get summary id of the node. */
+ inline int get_summary_id ()
+ {
+ return m_summary_id;
+ }
+
/* Record that DECL1 and DECL2 are semantically identical function
versions. */
static void record_function_versions (tree decl1, tree decl2);
@@ -1470,6 +1476,9 @@ private:
/* Unique id of the node. */
int m_uid;
+ /* Summary id that is recycled. */
+ int m_summary_id;
+
/* Worker for call_for_symbol_and_aliases. */
bool call_for_symbol_and_aliases_1 (bool (*callback) (cgraph_node *,
void *),
@@ -1728,6 +1737,12 @@ struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
return m_uid;
}
+ /* Get summary id of the edge. */
+ inline int get_summary_id ()
+ {
+ return m_summary_id;
+ }
+
/* Rebuild cgraph edges for current function node. This needs to be run after
passes that don't update the cgraph. */
static unsigned int rebuild_edges (void);
@@ -1805,6 +1820,9 @@ private:
/* Unique id of the edge. */
int m_uid;
+ /* Summary id that is recycled. */
+ int m_summary_id;
+
/* Remove the edge from the list of the callers of the callee. */
void remove_caller (void);
@@ -2051,7 +2069,8 @@ public:
friend class cgraph_node;
friend class cgraph_edge;
- symbol_table (): cgraph_max_uid (1), edges_max_uid (1)
+ symbol_table (): cgraph_max_uid (1), cgraph_max_summary_id (0),
+ edges_max_uid (1), edges_max_summary_id (0)
{
}
@@ -2254,15 +2273,31 @@ public:
/* Dump symbol table to stderr. */
void DEBUG_FUNCTION debug (void);
+ /* Assign a new summary ID for the callgraph NODE. */
+ inline int assign_summary_id (cgraph_node *node)
+ {
+ node->m_summary_id = cgraph_max_summary_id++;
+ return node->m_summary_id;
+ }
+
+ /* Assign a new summary ID for the callgraph EDGE. */
+ inline int assign_summary_id (cgraph_edge *edge)
+ {
+ edge->m_summary_id = edges_max_summary_id++;
+ return edge->m_summary_id;
+ }
+
/* Return true if assembler names NAME1 and NAME2 leads to the same symbol
name. */
static bool assembler_names_equal_p (const char *name1, const char *name2);
int cgraph_count;
int cgraph_max_uid;
+ int cgraph_max_summary_id;
int edges_count;
int edges_max_uid;
+ int edges_max_summary_id;
symtab_node* GTY(()) nodes;
asm_node* GTY(()) asmnodes;
@@ -2634,8 +2669,10 @@ symbol_table::release_symbol (cgraph_node *node)
/* Clear out the node to NULL all pointers and add the node to the free
list. */
+ int summary_id = node->m_summary_id;
memset (node, 0, sizeof (*node));
node->type = SYMTAB_FUNCTION;
+ node->m_summary_id = summary_id;
SET_NEXT_FREE_NODE (node, free_nodes);
free_nodes = node;
}
@@ -2653,7 +2690,10 @@ symbol_table::allocate_cgraph_symbol (void)
free_nodes = NEXT_FREE_NODE (node);
}
else
- node = ggc_cleared_alloc<cgraph_node> ();
+ {
+ node = ggc_cleared_alloc<cgraph_node> ();
+ node->m_summary_id = -1;
+ }
node->m_uid = cgraph_max_uid++;
return node;
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 260315da228..160261d34c9 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -85,8 +85,8 @@ along with GCC; see the file COPYING3. If not see
#include "attribs.h"
/* Summaries. */
-function_summary <ipa_fn_summary *> *ipa_fn_summaries;
-call_summary <ipa_call_summary *> *ipa_call_summaries;
+fast_function_summary <ipa_fn_summary *, va_gc> *ipa_fn_summaries;
+fast_call_summary <ipa_call_summary *, va_heap> *ipa_call_summaries;
/* Edge predicates goes here. */
static object_allocator<predicate> edge_predicate_pool ("edge predicates");
@@ -532,7 +532,7 @@ ipa_fn_summary_alloc (void)
{
gcc_checking_assert (!ipa_fn_summaries);
ipa_fn_summaries = ipa_fn_summary_t::create_ggc (symtab);
- ipa_call_summaries = new ipa_call_summary_t (symtab, false);
+ ipa_call_summaries = new ipa_call_summary_t (symtab);
}
ipa_call_summary::~ipa_call_summary ()
diff --git a/gcc/ipa-fnsummary.h b/gcc/ipa-fnsummary.h
index f1642a344d0..0f08e84ed53 100644
--- a/gcc/ipa-fnsummary.h
+++ b/gcc/ipa-fnsummary.h
@@ -173,16 +173,17 @@ struct GTY(()) ipa_fn_summary
static const int size_scale = 2;
};
-class GTY((user)) ipa_fn_summary_t: public function_summary <ipa_fn_summary *>
+class GTY((user)) ipa_fn_summary_t:
+ public fast_function_summary <ipa_fn_summary *, va_gc>
{
public:
- ipa_fn_summary_t (symbol_table *symtab, bool ggc):
- function_summary <ipa_fn_summary *> (symtab, ggc) {}
+ ipa_fn_summary_t (symbol_table *symtab):
+ fast_function_summary <ipa_fn_summary *, va_gc> (symtab) {}
static ipa_fn_summary_t *create_ggc (symbol_table *symtab)
{
struct ipa_fn_summary_t *summary = new (ggc_alloc <ipa_fn_summary_t> ())
- ipa_fn_summary_t(symtab, true);
+ ipa_fn_summary_t (symtab);
summary->disable_insertion_hook ();
return summary;
}
@@ -200,7 +201,8 @@ public:
ipa_fn_summary *src_data, ipa_fn_summary *dst_data);
};
-extern GTY(()) function_summary <ipa_fn_summary *> *ipa_fn_summaries;
+extern GTY(()) fast_function_summary <ipa_fn_summary *, va_gc>
+ *ipa_fn_summaries;
/* Information kept about callgraph edges. */
struct ipa_call_summary
@@ -236,11 +238,11 @@ struct ipa_call_summary
bool is_return_callee_uncaptured;
};
-class ipa_call_summary_t: public call_summary <ipa_call_summary *>
+class ipa_call_summary_t: public fast_call_summary <ipa_call_summary *, va_heap>
{
public:
- ipa_call_summary_t (symbol_table *symtab, bool ggc):
- call_summary <ipa_call_summary *> (symtab, ggc) {}
+ ipa_call_summary_t (symbol_table *symtab):
+ fast_call_summary <ipa_call_summary *, va_heap> (symtab) {}
/* Hook that is called by summary when an edge is duplicated. */
virtual void duplicate (cgraph_edge *src, cgraph_edge *dst,
@@ -248,7 +250,7 @@ public:
ipa_call_summary *dst_data);
};
-extern call_summary <ipa_call_summary *> *ipa_call_summaries;
+extern fast_call_summary <ipa_call_summary *, va_heap> *ipa_call_summaries;
/* In ipa-fnsummary.c */
void ipa_debug_fn_summary (struct cgraph_node *);
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index 3b3f2d8b4c5..bb561d00853 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -128,11 +128,12 @@ typedef struct funct_state_d * funct_state;
possibility that it may be desirable to move this to the cgraph
local info. */
-class funct_state_summary_t: public function_summary <funct_state_d *>
+class funct_state_summary_t:
+ public fast_function_summary <funct_state_d *, va_heap>
{
public:
funct_state_summary_t (symbol_table *symtab):
- function_summary <funct_state_d *> (symtab) {}
+ fast_function_summary <funct_state_d *, va_heap> (symtab) {}
virtual void insert (cgraph_node *, funct_state_d *state);
virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node,
diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c
index d1759a374bc..9ef03c2505b 100644
--- a/gcc/ipa-reference.c
+++ b/gcc/ipa-reference.c
@@ -110,23 +110,22 @@ static bitmap_obstack local_info_obstack;
/* Obstack holding global analysis live forever. */
static bitmap_obstack optimization_summary_obstack;
-class ipa_ref_var_info_summary_t: public function_summary
- <ipa_reference_vars_info_d *>
+class ipa_ref_var_info_summary_t: public fast_function_summary
+ <ipa_reference_vars_info_d *, va_heap>
{
public:
ipa_ref_var_info_summary_t (symbol_table *symtab):
- function_summary <ipa_reference_vars_info_d *> (symtab) {}
+ fast_function_summary <ipa_reference_vars_info_d *, va_heap> (symtab) {}
};
static ipa_ref_var_info_summary_t *ipa_ref_var_info_summaries = NULL;
-class ipa_ref_opt_summary_t: public function_summary
- <ipa_reference_optimization_summary_d *>
+class ipa_ref_opt_summary_t: public fast_function_summary
+ <ipa_reference_optimization_summary_d *, va_heap>
{
public:
ipa_ref_opt_summary_t (symbol_table *symtab):
- function_summary <ipa_reference_optimization_summary_d *> (symtab) {}
-
+ fast_function_summary <ipa_reference_optimization_summary_d *, va_heap> (symtab) {}
virtual void remove (cgraph_node *src_node,
ipa_reference_optimization_summary_d *data);
diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h
index f2378cdd749..0219f3a81ea 100644
--- a/gcc/symbol-summary.h
+++ b/gcc/symbol-summary.h
@@ -21,6 +21,90 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_SYMBOL_SUMMARY_H
#define GCC_SYMBOL_SUMMARY_H
+/* Base class for function_summary and fast_function_summary classes. */
+
+template <class T>
+class function_summary_base
+{
+public:
+ /* Default construction takes SYMTAB as an argument. */
+ function_summary_base (symbol_table *symtab): m_symtab (symtab),
+ m_insertion_enabled (true), m_released (false)
+ {}
+
+ /* Basic implementation of insert operation. */
+ virtual void insert (cgraph_node *, T *) {}
+
+ /* Basic implementation of removal operation. */
+ virtual void remove (cgraph_node *, T *) {}
+
+ /* Basic implementation of duplication operation. */
+ virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *) {}
+
+ /* Enable insertion hook invocation. */
+ void enable_insertion_hook ()
+ {
+ m_insertion_enabled = true;
+ }
+
+ /* Enable insertion hook invocation. */
+ void disable_insertion_hook ()
+ {
+ m_insertion_enabled = false;
+ }
+
+protected:
+ /* Allocates new data that are stored within map. */
+ T* allocate_new ()
+ {
+ /* Call gcc_internal_because we do not want to call finalizer for
+ a type T. We call dtor explicitly. */
+ return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
+ }
+
+ /* Release an item that is stored within map. */
+ void release (T *item)
+ {
+ if (is_ggc ())
+ {
+ item->~T ();
+ ggc_free (item);
+ }
+ else
+ delete item;
+ }
+
+ /* Unregister all call-graph hooks. */
+ void unregister_hooks ();
+
+ /* Internal summary insertion hook pointer. */
+ cgraph_node_hook_list *m_symtab_insertion_hook;
+ /* Internal summary removal hook pointer. */
+ cgraph_node_hook_list *m_symtab_removal_hook;
+ /* Internal summary duplication hook pointer. */
+ cgraph_2node_hook_list *m_symtab_duplication_hook;
+ /* Symbol table the summary is registered to. */
+ symbol_table *m_symtab;
+
+ /* Indicates if insertion hook is enabled. */
+ bool m_insertion_enabled;
+ /* Indicates if the summary is released. */
+ bool m_released;
+
+private:
+ /* Return true when the summary uses GGC memory for allocation. */
+ virtual bool is_ggc () = 0;
+};
+
+template <typename T>
+void
+function_summary_base<T>::unregister_hooks ()
+{
+ m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook);
+ m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook);
+ m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook);
+}
+
/* We want to pass just pointer types as argument for function_summary
template class. */
@@ -43,7 +127,7 @@ private:
a memory gained by garbage collected memory. */
template <class T>
-class GTY((user)) function_summary <T *>
+class GTY((user)) function_summary <T *>: public function_summary_base<T>
{
public:
/* Default construction takes SYMTAB as an argument. */
@@ -55,7 +139,8 @@ public:
release ();
}
- /* Destruction method that can be called for GGT purpose. */
+ /* Destruction method that can be called for GGC purpose. */
+ using function_summary_base<T>::release;
void release ();
/* Traverses all summarys with a function F called with
@@ -66,26 +151,6 @@ public:
m_map.traverse <f> (a);
}
- /* Basic implementation of insert operation. */
- virtual void insert (cgraph_node *, T *) {}
-
- /* Basic implementation of removal operation. */
- virtual void remove (cgraph_node *, T *) {}
-
- /* Basic implementation of duplication operation. */
- virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *) {}
-
- /* Allocates new data that are stored within map. */
- T* allocate_new ()
- {
- /* Call gcc_internal_because we do not want to call finalizer for
- a type T. We call dtor explicitly. */
- return m_ggc ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
- }
-
- /* Release an item that is stored within map. */
- void release (T *item);
-
/* Getter for summary callgraph node pointer. If a summary for a node
does not exist it will be created. */
T* get_create (cgraph_node *node)
@@ -93,7 +158,7 @@ public:
bool existed;
T **v = &m_map.get_or_insert (node->get_uid (), &existed);
if (!existed)
- *v = allocate_new ();
+ *v = this->allocate_new ();
return *v;
}
@@ -106,6 +171,7 @@ public:
}
/* Remove node from summary. */
+ using function_summary_base<T>::remove;
void remove (cgraph_node *node)
{
int uid = node->get_uid ();
@@ -113,34 +179,16 @@ public:
if (v)
{
m_map.remove (uid);
- release (*v);
+ this->release (*v);
}
}
- /* Return number of elements handled by data structure. */
- size_t elements ()
- {
- return m_map.elements ();
- }
-
/* Return true if a summary for the given NODE already exists. */
bool exists (cgraph_node *node)
{
return m_map.get (node->get_uid ()) != NULL;
}
- /* Enable insertion hook invocation. */
- void enable_insertion_hook ()
- {
- m_insertion_enabled = true;
- }
-
- /* Enable insertion hook invocation. */
- void disable_insertion_hook ()
- {
- m_insertion_enabled = false;
- }
-
/* Symbol insertion hook that is registered to symbol table. */
static void symtab_insertion (cgraph_node *node, void *data);
@@ -156,22 +204,16 @@ protected:
bool m_ggc;
private:
+ /* Indication if we use ggc summary. */
+ virtual bool is_ggc ()
+ {
+ return m_ggc;
+ }
+
typedef int_hash <int, 0, -1> map_hash;
- /* Indicates if insertion hook is enabled. */
- bool m_insertion_enabled;
- /* Indicates if the summary is released. */
- bool m_released;
/* Main summary store, where summary ID is used as key. */
hash_map <map_hash, T *> m_map;
- /* Internal summary insertion hook pointer. */
- cgraph_node_hook_list *m_symtab_insertion_hook;
- /* Internal summary removal hook pointer. */
- cgraph_node_hook_list *m_symtab_removal_hook;
- /* Internal summary duplication hook pointer. */
- cgraph_2node_hook_list *m_symtab_duplication_hook;
- /* Symbol table the summary is registered to. */
- symbol_table *m_symtab;
template <typename U> friend void gt_ggc_mx (function_summary <U *> * const &);
template <typename U> friend void gt_pch_nx (function_summary <U *> * const &);
@@ -181,50 +223,34 @@ private:
template <typename T>
function_summary<T *>::function_summary (symbol_table *symtab, bool ggc):
- m_ggc (ggc), m_insertion_enabled (true), m_released (false), m_map (13, ggc),
- m_symtab (symtab)
+ function_summary_base<T> (symtab), m_ggc (ggc), m_map (13, ggc)
{
- m_symtab_insertion_hook
- = symtab->add_cgraph_insertion_hook (function_summary::symtab_insertion,
- this);
-
- m_symtab_removal_hook
- = symtab->add_cgraph_removal_hook (function_summary::symtab_removal, this);
- m_symtab_duplication_hook
- = symtab->add_cgraph_duplication_hook (function_summary::symtab_duplication,
- this);
+ this->m_symtab_insertion_hook
+ = this->m_symtab->add_cgraph_insertion_hook (function_summary::symtab_insertion,
+ this);
+ this->m_symtab_removal_hook
+ = this->m_symtab->add_cgraph_removal_hook (function_summary::symtab_removal,
+ this);
+ this->m_symtab_duplication_hook
+ = this->m_symtab->add_cgraph_duplication_hook (function_summary::symtab_duplication,
+ this);
}
template <typename T>
void
function_summary<T *>::release ()
{
- if (m_released)
+ if (this->m_released)
return;
- m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook);
- m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook);
- m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook);
+ this->unregister_hooks ();
/* Release all summaries. */
typedef typename hash_map <map_hash, T *>::iterator map_iterator;
for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
- release ((*it).second);
+ this->release ((*it).second);
- m_released = true;
-}
-
-template <typename T>
-void
-function_summary<T *>::release (T *item)
-{
- if (m_ggc)
- {
- item->~T ();
- ggc_free (item);
- }
- else
- delete item;
+ this->m_released = true;
}
template <typename T>
@@ -244,19 +270,7 @@ function_summary<T *>::symtab_removal (cgraph_node *node, void *data)
{
gcc_checking_assert (node->get_uid ());
function_summary *summary = (function_summary <T *> *) (data);
-
- int uid = node->get_uid ();
- T **v = summary->m_map.get (uid);
-
- if (v)
- {
- summary->remove (node, *v);
-
- if (!summary->m_ggc)
- delete (*v);
-
- summary->m_map.remove (uid);
- }
+ summary->remove (node);
}
template <typename T>
@@ -268,12 +282,7 @@ function_summary<T *>::symtab_duplication (cgraph_node *node,
T *v = summary->get (node);
if (v)
- {
- /* This load is necessary, because we insert a new value! */
- T *duplicate = summary->allocate_new ();
- summary->m_map.put (node2->get_uid (), duplicate);
- summary->duplicate (node, node2, v, duplicate);
- }
+ summary->duplicate (node, node2, v, summary->get_create (node2));
}
template <typename T>
@@ -301,42 +310,49 @@ gt_pch_nx(function_summary<T *>* const& summary, gt_pointer_operator op,
gt_pch_nx (&summary->m_map, op, cookie);
}
-/* An impossible class templated by non-pointers so, which makes sure that only
- summaries gathering pointers can be created. */
+/* Help template from std c++11. */
-template <class T>
-class call_summary
+template<typename T, typename U>
+struct is_same
+{
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T,T> //specialization
+{
+ static const bool value = true;
+};
+
+/* We want to pass just pointer types as argument for fast_function_summary
+ template class. */
+
+template <class T, class V>
+class fast_function_summary
{
private:
- call_summary();
+ fast_function_summary ();
};
-/* Class to store auxiliary information about call graph edges. */
+/* Function vector summary is a fast implementation of function_summary that
+ utilizes vector as primary storage of summaries. */
-template <class T>
-class GTY((user)) call_summary <T *>
+template <class T, class V>
+class GTY((user)) fast_function_summary <T *, V>
+ : public function_summary_base<T>
{
public:
/* Default construction takes SYMTAB as an argument. */
- call_summary (symbol_table *symtab, bool ggc = false): m_ggc (ggc),
- m_initialize_when_cloning (false), m_map (13, ggc), m_released (false),
- m_symtab (symtab)
- {
- m_symtab_removal_hook =
- symtab->add_edge_removal_hook
- (call_summary::symtab_removal, this);
- m_symtab_duplication_hook =
- symtab->add_edge_duplication_hook
- (call_summary::symtab_duplication, this);
- }
+ fast_function_summary (symbol_table *symtab);
/* Destructor. */
- virtual ~call_summary ()
+ virtual ~fast_function_summary ()
{
release ();
}
- /* Destruction method that can be called for GGT purpose. */
+ /* Destruction method that can be called for GGC purpose. */
+ using function_summary_base<T>::release;
void release ();
/* Traverses all summarys with a function F called with
@@ -344,25 +360,309 @@ public:
template<typename Arg, bool (*f)(const T &, Arg)>
void traverse (Arg a) const
{
- m_map.traverse <f> (a);
+ for (unsigned i = 0; i < m_vector->length (); i++)
+ if ((*m_vector[i]) != NULL)
+ f ((*m_vector)[i]);
+ }
+
+ /* Getter for summary callgraph node pointer. If a summary for a node
+ does not exist it will be created. */
+ T* get_create (cgraph_node *node)
+ {
+ int id = node->get_summary_id ();
+ if (id == -1)
+ id = this->m_symtab->assign_summary_id (node);
+
+ if ((unsigned int)id >= m_vector->length ())
+ vec_safe_grow_cleared (m_vector,
+ this->m_symtab->cgraph_max_summary_id);
+
+ if ((*m_vector)[id] == NULL)
+ (*m_vector)[id] = this->allocate_new ();
+
+ return (*m_vector)[id];
+ }
+
+ /* Getter for summary callgraph node pointer. */
+ T* get (cgraph_node *node) ATTRIBUTE_PURE
+ {
+ return exists (node) ? (*m_vector)[node->get_summary_id ()] : NULL;
}
+ using function_summary_base<T>::remove;
+ void remove (cgraph_node *node)
+ {
+ if (exists (node))
+ {
+ int id = node->get_summary_id ();
+ this->release ((*m_vector)[id]);
+ (*m_vector)[id] = NULL;
+ }
+ }
+
+ /* Return true if a summary for the given NODE already exists. */
+ bool exists (cgraph_node *node)
+ {
+ int id = node->get_summary_id ();
+ return (id != -1
+ && (unsigned int)id < m_vector->length ()
+ && (*m_vector)[id] != NULL);
+ }
+
+ /* Symbol insertion hook that is registered to symbol table. */
+ static void symtab_insertion (cgraph_node *node, void *data);
+
+ /* Symbol removal hook that is registered to symbol table. */
+ static void symtab_removal (cgraph_node *node, void *data);
+
+ /* Symbol duplication hook that is registered to symbol table. */
+ static void symtab_duplication (cgraph_node *node, cgraph_node *node2,
+ void *data);
+
+private:
+ virtual bool is_ggc ();
+
+ /* Summary is stored in the vector. */
+ vec <T *, V> *m_vector;
+
+ template <typename U> friend void gt_ggc_mx (fast_function_summary <U *, va_gc> * const &);
+ template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &);
+ template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &,
+ gt_pointer_operator, void *);
+};
+
+template <typename T, typename V>
+fast_function_summary<T *, V>::fast_function_summary (symbol_table *symtab):
+ function_summary_base<T> (symtab), m_vector (NULL)
+{
+ vec_alloc (m_vector, 13);
+ this->m_symtab_insertion_hook
+ = this->m_symtab->add_cgraph_insertion_hook (fast_function_summary::symtab_insertion,
+ this);
+ this->m_symtab_removal_hook
+ = this->m_symtab->add_cgraph_removal_hook (fast_function_summary::symtab_removal,
+ this);
+ this->m_symtab_duplication_hook
+ = this->m_symtab->add_cgraph_duplication_hook (fast_function_summary::symtab_duplication,
+ this);
+}
+
+template <typename T, typename V>
+void
+fast_function_summary<T *, V>::release ()
+{
+ if (this->m_released)
+ return;
+
+ this->unregister_hooks ();
+
+ /* Release all summaries. */
+ for (unsigned i = 0; i < m_vector->length (); i++)
+ if ((*m_vector)[i] != NULL)
+ this->release ((*m_vector)[i]);
+
+ this->m_released = true;
+}
+
+template <typename T, typename V>
+void
+fast_function_summary<T *, V>::symtab_insertion (cgraph_node *node, void *data)
+{
+ gcc_checking_assert (node->get_uid ());
+ fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
+
+ if (summary->m_insertion_enabled)
+ summary->insert (node, summary->get_create (node));
+}
+
+template <typename T, typename V>
+void
+fast_function_summary<T *, V>::symtab_removal (cgraph_node *node, void *data)
+{
+ gcc_checking_assert (node->get_uid ());
+ fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
+
+ if (summary->exists (node))
+ summary->remove (node);
+}
+
+template <typename T, typename V>
+void
+fast_function_summary<T *, V>::symtab_duplication (cgraph_node *node,
+ cgraph_node *node2,
+ void *data)
+{
+ fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
+ T *v = summary->get (node);
+
+ if (v)
+ {
+ T *duplicate = summary->get_create (node2);
+ summary->duplicate (node, node2, v, duplicate);
+ }
+}
+
+template <typename T, typename V>
+inline bool
+fast_function_summary<T *, V>::is_ggc ()
+{
+ return is_same<V, va_gc>::value;
+}
+
+template <typename T>
+void
+gt_ggc_mx (fast_function_summary<T *, va_heap>* const &)
+{
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_function_summary<T *, va_heap>* const &)
+{
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_function_summary<T *, va_heap>* const&, gt_pointer_operator,
+ void *)
+{
+}
+
+template <typename T>
+void
+gt_ggc_mx (fast_function_summary<T *, va_gc>* const &summary)
+{
+ ggc_test_and_set_mark (summary->m_vector);
+ gt_ggc_mx (summary->m_vector);
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_function_summary<T *, va_gc>* const &summary)
+{
+ gt_pch_nx (summary->m_vector);
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_function_summary<T *, va_gc>* const& summary,
+ gt_pointer_operator op,
+ void *cookie)
+{
+ gt_pch_nx (summary->m_vector, op, cookie);
+}
+
+/* Base class for call_summary and fast_call_summary classes. */
+
+template <class T>
+class call_summary_base
+{
+public:
+ /* Default construction takes SYMTAB as an argument. */
+ call_summary_base (symbol_table *symtab): m_symtab (symtab),
+ m_initialize_when_cloning (true), m_released (false)
+ {}
+
/* Basic implementation of removal operation. */
virtual void remove (cgraph_edge *, T *) {}
/* Basic implementation of duplication operation. */
virtual void duplicate (cgraph_edge *, cgraph_edge *, T *, T *) {}
+protected:
/* Allocates new data that are stored within map. */
T* allocate_new ()
{
/* Call gcc_internal_because we do not want to call finalizer for
a type T. We call dtor explicitly. */
- return m_ggc ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
+ return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
}
/* Release an item that is stored within map. */
- void release (T *item);
+ void release (T *item)
+ {
+ if (is_ggc ())
+ {
+ item->~T ();
+ ggc_free (item);
+ }
+ else
+ delete item;
+ }
+
+ /* Unregister all call-graph hooks. */
+ void unregister_hooks ();
+
+ /* Symbol table the summary is registered to. */
+ symbol_table *m_symtab;
+
+ /* Internal summary removal hook pointer. */
+ cgraph_edge_hook_list *m_symtab_removal_hook;
+ /* Internal summary duplication hook pointer. */
+ cgraph_2edge_hook_list *m_symtab_duplication_hook;
+ /* Initialize summary for an edge that is cloned. */
+ bool m_initialize_when_cloning;
+ /* Indicates if the summary is released. */
+ bool m_released;
+
+private:
+ /* Return true when the summary uses GGC memory for allocation. */
+ virtual bool is_ggc () = 0;
+};
+
+template <typename T>
+void
+call_summary_base<T>::unregister_hooks ()
+{
+ m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
+ m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
+}
+
+/* An impossible class templated by non-pointers so, which makes sure that only
+ summaries gathering pointers can be created. */
+
+template <class T>
+class call_summary
+{
+private:
+ call_summary ();
+};
+
+/* Class to store auxiliary information about call graph edges. */
+
+template <class T>
+class GTY((user)) call_summary <T *>: public call_summary_base<T>
+{
+public:
+ /* Default construction takes SYMTAB as an argument. */
+ call_summary (symbol_table *symtab, bool ggc = false)
+ : call_summary_base<T> (symtab), m_ggc (ggc), m_map (13, ggc)
+ {
+ this->m_symtab_removal_hook
+ = this->m_symtab->add_edge_removal_hook (call_summary::symtab_removal,
+ this);
+ this->m_symtab_duplication_hook
+ = this->m_symtab->add_edge_duplication_hook (call_summary::symtab_duplication,
+ this);
+ }
+
+ /* Destructor. */
+ virtual ~call_summary ()
+ {
+ release ();
+ }
+
+ /* Destruction method that can be called for GGC purpose. */
+ using call_summary_base<T>::release;
+ void release ();
+
+ /* Traverses all summarys with an edge E called with
+ ARG as argument. */
+ template<typename Arg, bool (*f)(const T &, Arg)>
+ void traverse (Arg a) const
+ {
+ m_map.traverse <f> (a);
+ }
/* Getter for summary callgraph edge pointer.
If a summary for an edge does not exist, it will be created. */
@@ -371,7 +671,7 @@ public:
bool existed;
T **v = &m_map.get_or_insert (edge->get_uid (), &existed);
if (!existed)
- *v = allocate_new ();
+ *v = this->allocate_new ();
return *v;
}
@@ -384,6 +684,7 @@ public:
}
/* Remove edge from summary. */
+ using call_summary_base<T>::remove;
void remove (cgraph_edge *edge)
{
int uid = edge->get_uid ();
@@ -391,16 +692,10 @@ public:
if (v)
{
m_map.remove (uid);
- release (*v);
+ this->release (*v);
}
}
- /* Return number of elements handled by data structure. */
- size_t elements ()
- {
- return m_map.elements ();
- }
-
/* Return true if a summary for the given EDGE already exists. */
bool exists (cgraph_edge *edge)
{
@@ -418,22 +713,17 @@ protected:
/* Indication if we use ggc summary. */
bool m_ggc;
- /* Initialize summary for an edge that is cloned. */
- bool m_initialize_when_cloning;
-
private:
+ /* Indication if we use ggc summary. */
+ virtual bool is_ggc ()
+ {
+ return m_ggc;
+ }
+
typedef int_hash <int, 0, -1> map_hash;
/* Main summary store, where summary ID is used as key. */
hash_map <map_hash, T *> m_map;
- /* Internal summary removal hook pointer. */
- cgraph_edge_hook_list *m_symtab_removal_hook;
- /* Internal summary duplication hook pointer. */
- cgraph_2edge_hook_list *m_symtab_duplication_hook;
- /* Indicates if the summary is released. */
- bool m_released;
- /* Symbol table the summary is registered to. */
- symbol_table *m_symtab;
template <typename U> friend void gt_ggc_mx (call_summary <U *> * const &);
template <typename U> friend void gt_pch_nx (call_summary <U *> * const &);
@@ -445,31 +735,17 @@ template <typename T>
void
call_summary<T *>::release ()
{
- if (m_released)
+ if (this->m_released)
return;
- m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
- m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
+ this->unregister_hooks ();
/* Release all summaries. */
typedef typename hash_map <map_hash, T *>::iterator map_iterator;
for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
- release ((*it).second);
+ this->release ((*it).second);
- m_released = true;
-}
-
-template <typename T>
-void
-call_summary<T *>::release (T *item)
-{
- if (m_ggc)
- {
- item->~T ();
- ggc_free (item);
- }
- else
- delete item;
+ this->m_released = true;
}
template <typename T>
@@ -477,16 +753,7 @@ void
call_summary<T *>::symtab_removal (cgraph_edge *edge, void *data)
{
call_summary *summary = (call_summary <T *> *) (data);
-
- int h_uid = edge->get_uid ();
- T **v = summary->m_map.get (h_uid);
-
- if (v)
- {
- summary->remove (edge, *v);
- summary->release (*v);
- summary->m_map.remove (h_uid);
- }
+ summary->remove (edge);
}
template <typename T>
@@ -500,21 +767,11 @@ call_summary<T *>::symtab_duplication (cgraph_edge *edge1,
if (summary->m_initialize_when_cloning)
edge1_summary = summary->get_create (edge1);
else
- {
- T **v = summary->m_map.get (edge1->get_uid ());
- if (v)
- {
- /* This load is necessary, because we insert a new value! */
- edge1_summary = *v;
- }
- }
+ edge1_summary = summary->get (edge1);
if (edge1_summary)
- {
- T *duplicate = summary->allocate_new ();
- summary->m_map.put (edge2->get_uid (), duplicate);
- summary->duplicate (edge1, edge2, edge1_summary, duplicate);
- }
+ summary->duplicate (edge1, edge2, edge1_summary,
+ summary->get_create (edge2));
}
template <typename T>
@@ -542,4 +799,213 @@ gt_pch_nx(call_summary<T *>* const& summary, gt_pointer_operator op,
gt_pch_nx (&summary->m_map, op, cookie);
}
+/* We want to pass just pointer types as argument for fast_call_summary
+ template class. */
+
+template <class T, class V>
+class fast_call_summary
+{
+private:
+ fast_call_summary ();
+};
+
+/* Call vector summary is a fast implementation of call_summary that
+ utilizes vector as primary storage of summaries. */
+
+template <class T, class V>
+class GTY((user)) fast_call_summary <T *, V>: public call_summary_base<T>
+{
+public:
+ /* Default construction takes SYMTAB as an argument. */
+ fast_call_summary (symbol_table *symtab)
+ : call_summary_base<T> (symtab), m_vector (NULL)
+ {
+ vec_alloc (m_vector, 13);
+ this->m_symtab_removal_hook
+ = this->m_symtab->add_edge_removal_hook (fast_call_summary::symtab_removal,
+ this);
+ this->m_symtab_duplication_hook
+ = this->m_symtab->add_edge_duplication_hook (fast_call_summary::symtab_duplication,
+ this);
+ }
+
+ /* Destructor. */
+ virtual ~fast_call_summary ()
+ {
+ release ();
+ }
+
+ /* Destruction method that can be called for GGC purpose. */
+ using call_summary_base<T>::release;
+ void release ();
+
+ /* Traverses all summarys with an edge F called with
+ ARG as argument. */
+ template<typename Arg, bool (*f)(const T &, Arg)>
+ void traverse (Arg a) const
+ {
+ for (unsigned i = 0; i < m_vector->length (); i++)
+ if ((*m_vector[i]) != NULL)
+ f ((*m_vector)[i]);
+ }
+
+ /* Getter for summary callgraph edge pointer.
+ If a summary for an edge does not exist, it will be created. */
+ T* get_create (cgraph_edge *edge)
+ {
+ int id = edge->get_summary_id ();
+ if (id == -1)
+ id = this->m_symtab->assign_summary_id (edge);
+
+ if ((unsigned)id >= m_vector->length ())
+ vec_safe_grow_cleared (m_vector, this->m_symtab->edges_max_summary_id);
+
+ if ((*m_vector)[id] == NULL)
+ (*m_vector)[id] = this->allocate_new ();
+
+ return (*m_vector)[id];
+ }
+
+ /* Getter for summary callgraph edge pointer. */
+ T* get (cgraph_edge *edge) ATTRIBUTE_PURE
+ {
+ return exists (edge) ? (*m_vector)[edge->get_summary_id ()] : NULL;
+ }
+
+ /* Remove edge from summary. */
+ using call_summary_base<T>::remove;
+ void remove (cgraph_edge *edge)
+ {
+ if (exists (edge))
+ {
+ int id = edge->get_summary_id ();
+ this->release ((*m_vector)[id]);
+ (*m_vector)[id] = NULL;
+ }
+ }
+
+ /* Return true if a summary for the given EDGE already exists. */
+ bool exists (cgraph_edge *edge)
+ {
+ int id = edge->get_summary_id ();
+ return (id != -1
+ && (unsigned)id < m_vector->length ()
+ && (*m_vector)[id] != NULL);
+ }
+
+ /* Symbol removal hook that is registered to symbol table. */
+ static void symtab_removal (cgraph_edge *edge, void *data);
+
+ /* Symbol duplication hook that is registered to symbol table. */
+ static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2,
+ void *data);
+
+private:
+ virtual bool is_ggc ();
+
+ /* Summary is stored in the vector. */
+ vec <T *, V> *m_vector;
+
+ template <typename U> friend void gt_ggc_mx (fast_call_summary <U *, va_gc> * const &);
+ template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &);
+ template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &,
+ gt_pointer_operator, void *);
+};
+
+template <typename T, typename V>
+void
+fast_call_summary<T *, V>::release ()
+{
+ if (this->m_released)
+ return;
+
+ this->unregister_hooks ();
+
+ /* Release all summaries. */
+ for (unsigned i = 0; i < m_vector->length (); i++)
+ if ((*m_vector)[i] != NULL)
+ this->release ((*m_vector)[i]);
+
+ this->m_released = true;
+}
+
+template <typename T, typename V>
+void
+fast_call_summary<T *, V>::symtab_removal (cgraph_edge *edge, void *data)
+{
+ fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
+ summary->remove (edge);
+}
+
+template <typename T, typename V>
+void
+fast_call_summary<T *, V>::symtab_duplication (cgraph_edge *edge1,
+ cgraph_edge *edge2, void *data)
+{
+ fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
+ T *edge1_summary = NULL;
+
+ if (summary->m_initialize_when_cloning)
+ edge1_summary = summary->get_create (edge1);
+ else
+ edge1_summary = summary->get (edge1);
+
+ if (edge1_summary)
+ {
+ T *duplicate = summary->get_create (edge2);
+ summary->duplicate (edge1, edge2, edge1_summary, duplicate);
+ }
+}
+
+template <typename T, typename V>
+inline bool
+fast_call_summary<T *, V>::is_ggc ()
+{
+ return is_same<V, va_gc>::value;
+}
+
+template <typename T>
+void
+gt_ggc_mx (fast_call_summary<T *, va_heap>* const &summary)
+{
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_call_summary<T *, va_heap>* const &summary)
+{
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_call_summary<T *, va_heap>* const& summary,
+ gt_pointer_operator op,
+ void *cookie)
+{
+}
+
+template <typename T>
+void
+gt_ggc_mx (fast_call_summary<T *, va_gc>* const &summary)
+{
+ ggc_test_and_set_mark (summary->m_vector);
+ gt_ggc_mx (&summary->m_vector);
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_call_summary<T *, va_gc>* const &summary)
+{
+ gt_pch_nx (&summary->m_vector);
+}
+
+template <typename T>
+void
+gt_pch_nx (fast_call_summary<T *, va_gc>* const& summary,
+ gt_pointer_operator op,
+ void *cookie)
+{
+ gt_pch_nx (&summary->m_vector, op, cookie);
+}
+
#endif /* GCC_SYMBOL_SUMMARY_H */
diff --git a/gcc/vec.h b/gcc/vec.h
index 8c2a39b0b05..4bd9df9aba5 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -732,6 +732,17 @@ vec_safe_grow_cleared (vec<T, A, vl_embed> *&v, unsigned len CXX_MEM_STAT_INFO)
}
+/* Assume V is not NULL. */
+
+template<typename T>
+inline void
+vec_safe_grow_cleared (vec<T, va_heap, vl_ptr> *&v,
+ unsigned len CXX_MEM_STAT_INFO)
+{
+ v->safe_grow_cleared (len);
+}
+
+
/* If V is NULL return false, otherwise return V->iterate(IX, PTR). */
template<typename T, typename A>
inline bool
--
2.20.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Come up with fast {function,call}_summary classes (PR ipa/89306).
2019-02-15 11:42 [PATCH] Come up with fast {function,call}_summary classes (PR ipa/89306) Martin Liška
2019-02-15 12:09 ` Martin Liška
@ 2019-02-18 8:09 ` Jan Hubicka
1 sibling, 0 replies; 3+ messages in thread
From: Jan Hubicka @ 2019-02-18 8:09 UTC (permalink / raw)
To: Martin Liška; +Cc: gcc-patches, Martin Jambor
> Hi.
>
> The patch comes up with new summaries that use vector as underlying
> data structure. In order to make the code more readable I decided to
> factor out some common code into base classes.
>
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> I tested building Inkscape w/ LTO and Honza make the same testing
> for Firefox libxul.so.
>
> Ready to be installed?
Yes, during weekend I rebuilt Firefox and clang. The speedups are
somewhere between 3% to 15% of WPA time. Original analysis has
suggested more but in meantime some of the hashing based bottlenecks
went away mostly due to the patch that avoids creating summaries for
edges that will not be used.
Thanks for working on this, patch is OK.
Honza
> Thanks,
> Martin
>
> gcc/ChangeLog:
>
> 2019-02-13 Martin Liska <mliska@suse.cz>
>
> PR ipa/89306
> * cgraph.c (symbol_table::create_edge): Set m_summary_id to -1
> by default.
> (symbol_table::free_edge): Recycle m_summary_id.
> * cgraph.h (get_summary_id): New.
> (symbol_table::release_symbol): Set m_summary_id to -1
> by default.
> (symbol_table::allocate_cgraph_symbol): Recycle m_summary_id.
> * ipa-fnsummary.c (ipa_fn_summary_t): Switch from
> function_summary to fast_function_summary.
> * ipa-fnsummary.h (ipa_fn_summary_t): Likewise.
> * ipa-pure-const.c (class funct_state_summary_t):
> Switch from function_summary to fast_function_summary.
> * ipa-reference.c (class ipa_ref_var_info_summary_t): Likewise.
> (class ipa_ref_opt_summary_t): Switch from function_summary
> to fast_function_summary.
> * symbol-summary.h (class function_summary_base): New class
> that is created from base of former function_summary.
> (function_summary_base::unregister_hooks): New.
> (class function_summary): Inherit from function_summary_base.
> (class call_summary_base): New class
> that is created from base of former call_summary.
> (class call_summary): Inherit from call_summary_base.
> (struct is_same): New.
> (class fast_function_summary): New summary class.
> (class fast_call_summary): New summary class.
> * vec.h (vec_safe_grow_cleared): New function.
> ---
> gcc/cgraph.c | 7 +-
> gcc/cgraph.h | 44 ++-
> gcc/ipa-fnsummary.c | 6 +-
> gcc/ipa-fnsummary.h | 20 +-
> gcc/ipa-pure-const.c | 5 +-
> gcc/ipa-reference.c | 13 +-
> gcc/symbol-summary.h | 840 +++++++++++++++++++++++++++++++++----------
> gcc/vec.h | 11 +
> 8 files changed, 735 insertions(+), 211 deletions(-)
>
>
> diff --git a/gcc/cgraph.c b/gcc/cgraph.c
> index c9788d0286a..de82316d4b1 100644
> --- a/gcc/cgraph.c
> +++ b/gcc/cgraph.c
> @@ -852,7 +852,10 @@ symbol_table::create_edge (cgraph_node *caller, cgraph_node *callee,
> free_edges = NEXT_FREE_EDGE (edge);
> }
> else
> - edge = ggc_alloc<cgraph_edge> ();
> + {
> + edge = ggc_alloc<cgraph_edge> ();
> + edge->m_summary_id = -1;
> + }
>
> edges_count++;
>
> @@ -1014,7 +1017,9 @@ symbol_table::free_edge (cgraph_edge *e)
> ggc_free (e->indirect_info);
>
> /* Clear out the edge so we do not dangle pointers. */
> + int summary_id = e->m_summary_id;
> memset (e, 0, sizeof (*e));
> + e->m_summary_id = summary_id;
> NEXT_FREE_EDGE (e) = free_edges;
> free_edges = e;
> edges_count--;
> diff --git a/gcc/cgraph.h b/gcc/cgraph.h
> index 2f6daa75a24..03ae411acde 100644
> --- a/gcc/cgraph.h
> +++ b/gcc/cgraph.h
> @@ -1302,6 +1302,12 @@ public:
> return m_uid;
> }
>
> + /* Get summary id of the node. */
> + inline int get_summary_id ()
> + {
> + return m_summary_id;
> + }
> +
> /* Record that DECL1 and DECL2 are semantically identical function
> versions. */
> static void record_function_versions (tree decl1, tree decl2);
> @@ -1470,6 +1476,9 @@ private:
> /* Unique id of the node. */
> int m_uid;
>
> + /* Summary id that is recycled. */
> + int m_summary_id;
> +
> /* Worker for call_for_symbol_and_aliases. */
> bool call_for_symbol_and_aliases_1 (bool (*callback) (cgraph_node *,
> void *),
> @@ -1728,6 +1737,12 @@ struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
> return m_uid;
> }
>
> + /* Get summary id of the edge. */
> + inline int get_summary_id ()
> + {
> + return m_summary_id;
> + }
> +
> /* Rebuild cgraph edges for current function node. This needs to be run after
> passes that don't update the cgraph. */
> static unsigned int rebuild_edges (void);
> @@ -1805,6 +1820,9 @@ private:
> /* Unique id of the edge. */
> int m_uid;
>
> + /* Summary id that is recycled. */
> + int m_summary_id;
> +
> /* Remove the edge from the list of the callers of the callee. */
> void remove_caller (void);
>
> @@ -2051,7 +2069,8 @@ public:
> friend class cgraph_node;
> friend class cgraph_edge;
>
> - symbol_table (): cgraph_max_uid (1), edges_max_uid (1)
> + symbol_table (): cgraph_max_uid (1), cgraph_max_summary_id (0),
> + edges_max_uid (1), edges_max_summary_id (0)
> {
> }
>
> @@ -2254,15 +2273,31 @@ public:
> /* Dump symbol table to stderr. */
> void DEBUG_FUNCTION debug (void);
>
> + /* Allocate new callgraph node. */
> + inline int assign_summary_id (cgraph_node *node)
> + {
> + node->m_summary_id = cgraph_max_summary_id++;
> + return node->m_summary_id;
> + }
> +
> + /* Allocate new callgraph node. */
> + inline int assign_summary_id (cgraph_edge *edge)
> + {
> + edge->m_summary_id = edges_max_summary_id++;
> + return edge->m_summary_id;
> + }
> +
> /* Return true if assembler names NAME1 and NAME2 leads to the same symbol
> name. */
> static bool assembler_names_equal_p (const char *name1, const char *name2);
>
> int cgraph_count;
> int cgraph_max_uid;
> + int cgraph_max_summary_id;
>
> int edges_count;
> int edges_max_uid;
> + int edges_max_summary_id;
>
> symtab_node* GTY(()) nodes;
> asm_node* GTY(()) asmnodes;
> @@ -2634,8 +2669,10 @@ symbol_table::release_symbol (cgraph_node *node)
>
> /* Clear out the node to NULL all pointers and add the node to the free
> list. */
> + int summary_id = node->m_summary_id;
> memset (node, 0, sizeof (*node));
> node->type = SYMTAB_FUNCTION;
> + node->m_summary_id = summary_id;
> SET_NEXT_FREE_NODE (node, free_nodes);
> free_nodes = node;
> }
> @@ -2653,7 +2690,10 @@ symbol_table::allocate_cgraph_symbol (void)
> free_nodes = NEXT_FREE_NODE (node);
> }
> else
> - node = ggc_cleared_alloc<cgraph_node> ();
> + {
> + node = ggc_cleared_alloc<cgraph_node> ();
> + node->m_summary_id = -1;
> + }
>
> node->m_uid = cgraph_max_uid++;
> return node;
> diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
> index 260315da228..160261d34c9 100644
> --- a/gcc/ipa-fnsummary.c
> +++ b/gcc/ipa-fnsummary.c
> @@ -85,8 +85,8 @@ along with GCC; see the file COPYING3. If not see
> #include "attribs.h"
>
> /* Summaries. */
> -function_summary <ipa_fn_summary *> *ipa_fn_summaries;
> -call_summary <ipa_call_summary *> *ipa_call_summaries;
> +fast_function_summary <ipa_fn_summary *, va_gc> *ipa_fn_summaries;
> +fast_call_summary <ipa_call_summary *, va_heap> *ipa_call_summaries;
>
> /* Edge predicates goes here. */
> static object_allocator<predicate> edge_predicate_pool ("edge predicates");
> @@ -532,7 +532,7 @@ ipa_fn_summary_alloc (void)
> {
> gcc_checking_assert (!ipa_fn_summaries);
> ipa_fn_summaries = ipa_fn_summary_t::create_ggc (symtab);
> - ipa_call_summaries = new ipa_call_summary_t (symtab, false);
> + ipa_call_summaries = new ipa_call_summary_t (symtab);
> }
>
> ipa_call_summary::~ipa_call_summary ()
> diff --git a/gcc/ipa-fnsummary.h b/gcc/ipa-fnsummary.h
> index f1642a344d0..0f08e84ed53 100644
> --- a/gcc/ipa-fnsummary.h
> +++ b/gcc/ipa-fnsummary.h
> @@ -173,16 +173,17 @@ struct GTY(()) ipa_fn_summary
> static const int size_scale = 2;
> };
>
> -class GTY((user)) ipa_fn_summary_t: public function_summary <ipa_fn_summary *>
> +class GTY((user)) ipa_fn_summary_t:
> + public fast_function_summary <ipa_fn_summary *, va_gc>
> {
> public:
> - ipa_fn_summary_t (symbol_table *symtab, bool ggc):
> - function_summary <ipa_fn_summary *> (symtab, ggc) {}
> + ipa_fn_summary_t (symbol_table *symtab):
> + fast_function_summary <ipa_fn_summary *, va_gc> (symtab) {}
>
> static ipa_fn_summary_t *create_ggc (symbol_table *symtab)
> {
> struct ipa_fn_summary_t *summary = new (ggc_alloc <ipa_fn_summary_t> ())
> - ipa_fn_summary_t(symtab, true);
> + ipa_fn_summary_t (symtab);
> summary->disable_insertion_hook ();
> return summary;
> }
> @@ -200,7 +201,8 @@ public:
> ipa_fn_summary *src_data, ipa_fn_summary *dst_data);
> };
>
> -extern GTY(()) function_summary <ipa_fn_summary *> *ipa_fn_summaries;
> +extern GTY(()) fast_function_summary <ipa_fn_summary *, va_gc>
> + *ipa_fn_summaries;
>
> /* Information kept about callgraph edges. */
> struct ipa_call_summary
> @@ -236,11 +238,11 @@ struct ipa_call_summary
> bool is_return_callee_uncaptured;
> };
>
> -class ipa_call_summary_t: public call_summary <ipa_call_summary *>
> +class ipa_call_summary_t: public fast_call_summary <ipa_call_summary *, va_heap>
> {
> public:
> - ipa_call_summary_t (symbol_table *symtab, bool ggc):
> - call_summary <ipa_call_summary *> (symtab, ggc) {}
> + ipa_call_summary_t (symbol_table *symtab):
> + fast_call_summary <ipa_call_summary *, va_heap> (symtab) {}
>
> /* Hook that is called by summary when an edge is duplicated. */
> virtual void duplicate (cgraph_edge *src, cgraph_edge *dst,
> @@ -248,7 +250,7 @@ public:
> ipa_call_summary *dst_data);
> };
>
> -extern call_summary <ipa_call_summary *> *ipa_call_summaries;
> +extern fast_call_summary <ipa_call_summary *, va_heap> *ipa_call_summaries;
>
> /* In ipa-fnsummary.c */
> void ipa_debug_fn_summary (struct cgraph_node *);
> diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
> index 3b3f2d8b4c5..bb561d00853 100644
> --- a/gcc/ipa-pure-const.c
> +++ b/gcc/ipa-pure-const.c
> @@ -128,11 +128,12 @@ typedef struct funct_state_d * funct_state;
> possibility that it may be desirable to move this to the cgraph
> local info. */
>
> -class funct_state_summary_t: public function_summary <funct_state_d *>
> +class funct_state_summary_t:
> + public fast_function_summary <funct_state_d *, va_heap>
> {
> public:
> funct_state_summary_t (symbol_table *symtab):
> - function_summary <funct_state_d *> (symtab) {}
> + fast_function_summary <funct_state_d *, va_heap> (symtab) {}
>
> virtual void insert (cgraph_node *, funct_state_d *state);
> virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node,
> diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c
> index d1759a374bc..9ef03c2505b 100644
> --- a/gcc/ipa-reference.c
> +++ b/gcc/ipa-reference.c
> @@ -110,23 +110,22 @@ static bitmap_obstack local_info_obstack;
> /* Obstack holding global analysis live forever. */
> static bitmap_obstack optimization_summary_obstack;
>
> -class ipa_ref_var_info_summary_t: public function_summary
> - <ipa_reference_vars_info_d *>
> +class ipa_ref_var_info_summary_t: public fast_function_summary
> + <ipa_reference_vars_info_d *, va_heap>
> {
> public:
> ipa_ref_var_info_summary_t (symbol_table *symtab):
> - function_summary <ipa_reference_vars_info_d *> (symtab) {}
> + fast_function_summary <ipa_reference_vars_info_d *, va_heap> (symtab) {}
> };
>
> static ipa_ref_var_info_summary_t *ipa_ref_var_info_summaries = NULL;
>
> -class ipa_ref_opt_summary_t: public function_summary
> - <ipa_reference_optimization_summary_d *>
> +class ipa_ref_opt_summary_t: public fast_function_summary
> + <ipa_reference_optimization_summary_d *, va_heap>
> {
> public:
> ipa_ref_opt_summary_t (symbol_table *symtab):
> - function_summary <ipa_reference_optimization_summary_d *> (symtab) {}
> -
> + fast_function_summary <ipa_reference_optimization_summary_d *, va_heap> (symtab) {}
>
> virtual void remove (cgraph_node *src_node,
> ipa_reference_optimization_summary_d *data);
> diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h
> index f2378cdd749..0219f3a81ea 100644
> --- a/gcc/symbol-summary.h
> +++ b/gcc/symbol-summary.h
> @@ -21,6 +21,90 @@ along with GCC; see the file COPYING3. If not see
> #ifndef GCC_SYMBOL_SUMMARY_H
> #define GCC_SYMBOL_SUMMARY_H
>
> +/* Base class for function_summary and fast_function_summary classes. */
> +
> +template <class T>
> +class function_summary_base
> +{
> +public:
> + /* Default construction takes SYMTAB as an argument. */
> + function_summary_base (symbol_table *symtab): m_symtab (symtab),
> + m_insertion_enabled (true), m_released (false)
> + {}
> +
> + /* Basic implementation of insert operation. */
> + virtual void insert (cgraph_node *, T *) {}
> +
> + /* Basic implementation of removal operation. */
> + virtual void remove (cgraph_node *, T *) {}
> +
> + /* Basic implementation of duplication operation. */
> + virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *) {}
> +
> + /* Enable insertion hook invocation. */
> + void enable_insertion_hook ()
> + {
> + m_insertion_enabled = true;
> + }
> +
> + /* Enable insertion hook invocation. */
> + void disable_insertion_hook ()
> + {
> + m_insertion_enabled = false;
> + }
> +
> +protected:
> + /* Allocates new data that are stored within map. */
> + T* allocate_new ()
> + {
> + /* Call gcc_internal_because we do not want to call finalizer for
> + a type T. We call dtor explicitly. */
> + return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
> + }
> +
> + /* Release an item that is stored within map. */
> + void release (T *item)
> + {
> + if (is_ggc ())
> + {
> + item->~T ();
> + ggc_free (item);
> + }
> + else
> + delete item;
> + }
> +
> + /* Unregister all call-graph hooks. */
> + void unregister_hooks ();
> +
> + /* Internal summary insertion hook pointer. */
> + cgraph_node_hook_list *m_symtab_insertion_hook;
> + /* Internal summary removal hook pointer. */
> + cgraph_node_hook_list *m_symtab_removal_hook;
> + /* Internal summary duplication hook pointer. */
> + cgraph_2node_hook_list *m_symtab_duplication_hook;
> + /* Symbol table the summary is registered to. */
> + symbol_table *m_symtab;
> +
> + /* Indicates if insertion hook is enabled. */
> + bool m_insertion_enabled;
> + /* Indicates if the summary is released. */
> + bool m_released;
> +
> +private:
> + /* Return true when the summary uses GGC memory for allocation. */
> + virtual bool is_ggc () = 0;
> +};
> +
> +template <typename T>
> +void
> +function_summary_base<T>::unregister_hooks ()
> +{
> + m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook);
> + m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook);
> + m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook);
> +}
> +
> /* We want to pass just pointer types as argument for function_summary
> template class. */
>
> @@ -43,7 +127,7 @@ private:
> a memory gained by garbage collected memory. */
>
> template <class T>
> -class GTY((user)) function_summary <T *>
> +class GTY((user)) function_summary <T *>: public function_summary_base<T>
> {
> public:
> /* Default construction takes SYMTAB as an argument. */
> @@ -55,7 +139,8 @@ public:
> release ();
> }
>
> - /* Destruction method that can be called for GGT purpose. */
> + /* Destruction method that can be called for GGC purpose. */
> + using function_summary_base<T>::release;
> void release ();
>
> /* Traverses all summarys with a function F called with
> @@ -66,26 +151,6 @@ public:
> m_map.traverse <f> (a);
> }
>
> - /* Basic implementation of insert operation. */
> - virtual void insert (cgraph_node *, T *) {}
> -
> - /* Basic implementation of removal operation. */
> - virtual void remove (cgraph_node *, T *) {}
> -
> - /* Basic implementation of duplication operation. */
> - virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *) {}
> -
> - /* Allocates new data that are stored within map. */
> - T* allocate_new ()
> - {
> - /* Call gcc_internal_because we do not want to call finalizer for
> - a type T. We call dtor explicitly. */
> - return m_ggc ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
> - }
> -
> - /* Release an item that is stored within map. */
> - void release (T *item);
> -
> /* Getter for summary callgraph node pointer. If a summary for a node
> does not exist it will be created. */
> T* get_create (cgraph_node *node)
> @@ -93,7 +158,7 @@ public:
> bool existed;
> T **v = &m_map.get_or_insert (node->get_uid (), &existed);
> if (!existed)
> - *v = allocate_new ();
> + *v = this->allocate_new ();
>
> return *v;
> }
> @@ -106,6 +171,7 @@ public:
> }
>
> /* Remove node from summary. */
> + using function_summary_base<T>::remove;
> void remove (cgraph_node *node)
> {
> int uid = node->get_uid ();
> @@ -113,34 +179,16 @@ public:
> if (v)
> {
> m_map.remove (uid);
> - release (*v);
> + this->release (*v);
> }
> }
>
> - /* Return number of elements handled by data structure. */
> - size_t elements ()
> - {
> - return m_map.elements ();
> - }
> -
> /* Return true if a summary for the given NODE already exists. */
> bool exists (cgraph_node *node)
> {
> return m_map.get (node->get_uid ()) != NULL;
> }
>
> - /* Enable insertion hook invocation. */
> - void enable_insertion_hook ()
> - {
> - m_insertion_enabled = true;
> - }
> -
> - /* Enable insertion hook invocation. */
> - void disable_insertion_hook ()
> - {
> - m_insertion_enabled = false;
> - }
> -
> /* Symbol insertion hook that is registered to symbol table. */
> static void symtab_insertion (cgraph_node *node, void *data);
>
> @@ -156,22 +204,16 @@ protected:
> bool m_ggc;
>
> private:
> + /* Indication if we use ggc summary. */
> + virtual bool is_ggc ()
> + {
> + return m_ggc;
> + }
> +
> typedef int_hash <int, 0, -1> map_hash;
>
> - /* Indicates if insertion hook is enabled. */
> - bool m_insertion_enabled;
> - /* Indicates if the summary is released. */
> - bool m_released;
> /* Main summary store, where summary ID is used as key. */
> hash_map <map_hash, T *> m_map;
> - /* Internal summary insertion hook pointer. */
> - cgraph_node_hook_list *m_symtab_insertion_hook;
> - /* Internal summary removal hook pointer. */
> - cgraph_node_hook_list *m_symtab_removal_hook;
> - /* Internal summary duplication hook pointer. */
> - cgraph_2node_hook_list *m_symtab_duplication_hook;
> - /* Symbol table the summary is registered to. */
> - symbol_table *m_symtab;
>
> template <typename U> friend void gt_ggc_mx (function_summary <U *> * const &);
> template <typename U> friend void gt_pch_nx (function_summary <U *> * const &);
> @@ -181,50 +223,34 @@ private:
>
> template <typename T>
> function_summary<T *>::function_summary (symbol_table *symtab, bool ggc):
> - m_ggc (ggc), m_insertion_enabled (true), m_released (false), m_map (13, ggc),
> - m_symtab (symtab)
> + function_summary_base<T> (symtab), m_ggc (ggc), m_map (13, ggc)
> {
> - m_symtab_insertion_hook
> - = symtab->add_cgraph_insertion_hook (function_summary::symtab_insertion,
> - this);
> -
> - m_symtab_removal_hook
> - = symtab->add_cgraph_removal_hook (function_summary::symtab_removal, this);
> - m_symtab_duplication_hook
> - = symtab->add_cgraph_duplication_hook (function_summary::symtab_duplication,
> - this);
> + this->m_symtab_insertion_hook
> + = this->m_symtab->add_cgraph_insertion_hook (function_summary::symtab_insertion,
> + this);
> + this->m_symtab_removal_hook
> + = this->m_symtab->add_cgraph_removal_hook (function_summary::symtab_removal,
> + this);
> + this->m_symtab_duplication_hook
> + = this->m_symtab->add_cgraph_duplication_hook (function_summary::symtab_duplication,
> + this);
> }
>
> template <typename T>
> void
> function_summary<T *>::release ()
> {
> - if (m_released)
> + if (this->m_released)
> return;
>
> - m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook);
> - m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook);
> - m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook);
> + this->unregister_hooks ();
>
> /* Release all summaries. */
> typedef typename hash_map <map_hash, T *>::iterator map_iterator;
> for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
> - release ((*it).second);
> + this->release ((*it).second);
>
> - m_released = true;
> -}
> -
> -template <typename T>
> -void
> -function_summary<T *>::release (T *item)
> -{
> - if (m_ggc)
> - {
> - item->~T ();
> - ggc_free (item);
> - }
> - else
> - delete item;
> + this->m_released = true;
> }
>
> template <typename T>
> @@ -244,19 +270,7 @@ function_summary<T *>::symtab_removal (cgraph_node *node, void *data)
> {
> gcc_checking_assert (node->get_uid ());
> function_summary *summary = (function_summary <T *> *) (data);
> -
> - int uid = node->get_uid ();
> - T **v = summary->m_map.get (uid);
> -
> - if (v)
> - {
> - summary->remove (node, *v);
> -
> - if (!summary->m_ggc)
> - delete (*v);
> -
> - summary->m_map.remove (uid);
> - }
> + summary->remove (node);
> }
>
> template <typename T>
> @@ -268,12 +282,7 @@ function_summary<T *>::symtab_duplication (cgraph_node *node,
> T *v = summary->get (node);
>
> if (v)
> - {
> - /* This load is necessary, because we insert a new value! */
> - T *duplicate = summary->allocate_new ();
> - summary->m_map.put (node2->get_uid (), duplicate);
> - summary->duplicate (node, node2, v, duplicate);
> - }
> + summary->duplicate (node, node2, v, summary->get_create (node2));
> }
>
> template <typename T>
> @@ -301,42 +310,49 @@ gt_pch_nx(function_summary<T *>* const& summary, gt_pointer_operator op,
> gt_pch_nx (&summary->m_map, op, cookie);
> }
>
> -/* An impossible class templated by non-pointers so, which makes sure that only
> - summaries gathering pointers can be created. */
> +/* Help template from std c++11. */
>
> -template <class T>
> -class call_summary
> +template<typename T, typename U>
> +struct is_same
> +{
> + static const bool value = false;
> +};
> +
> +template<typename T>
> +struct is_same<T,T> //specialization
> +{
> + static const bool value = true;
> +};
> +
> +/* We want to pass just pointer types as argument for fast_function_summary
> + template class. */
> +
> +template <class T, class V>
> +class fast_function_summary
> {
> private:
> - call_summary();
> + fast_function_summary ();
> };
>
> -/* Class to store auxiliary information about call graph edges. */
> +/* Function vector summary is a fast implementation of function_summary that
> + utilizes vector as primary storage of summaries. */
>
> -template <class T>
> -class GTY((user)) call_summary <T *>
> +template <class T, class V>
> +class GTY((user)) fast_function_summary <T *, V>
> + : public function_summary_base<T>
> {
> public:
> /* Default construction takes SYMTAB as an argument. */
> - call_summary (symbol_table *symtab, bool ggc = false): m_ggc (ggc),
> - m_initialize_when_cloning (false), m_map (13, ggc), m_released (false),
> - m_symtab (symtab)
> - {
> - m_symtab_removal_hook =
> - symtab->add_edge_removal_hook
> - (call_summary::symtab_removal, this);
> - m_symtab_duplication_hook =
> - symtab->add_edge_duplication_hook
> - (call_summary::symtab_duplication, this);
> - }
> + fast_function_summary (symbol_table *symtab);
>
> /* Destructor. */
> - virtual ~call_summary ()
> + virtual ~fast_function_summary ()
> {
> release ();
> }
>
> - /* Destruction method that can be called for GGT purpose. */
> + /* Destruction method that can be called for GGC purpose. */
> + using function_summary_base<T>::release;
> void release ();
>
> /* Traverses all summarys with a function F called with
> @@ -344,25 +360,309 @@ public:
> template<typename Arg, bool (*f)(const T &, Arg)>
> void traverse (Arg a) const
> {
> - m_map.traverse <f> (a);
> + for (unsigned i = 0; i < m_vector->length (); i++)
> + if ((*m_vector[i]) != NULL)
> + f ((*m_vector)[i]);
> + }
> +
> + /* Getter for summary callgraph node pointer. If a summary for a node
> + does not exist it will be created. */
> + T* get_create (cgraph_node *node)
> + {
> + int id = node->get_summary_id ();
> + if (id == -1)
> + id = this->m_symtab->assign_summary_id (node);
> +
> + if ((unsigned int)id >= m_vector->length ())
> + vec_safe_grow_cleared (m_vector,
> + this->m_symtab->cgraph_max_summary_id);
> +
> + if ((*m_vector)[id] == NULL)
> + (*m_vector)[id] = this->allocate_new ();
> +
> + return (*m_vector)[id];
> + }
> +
> + /* Getter for summary callgraph node pointer. */
> + T* get (cgraph_node *node) ATTRIBUTE_PURE
> + {
> + return exists (node) ? (*m_vector)[node->get_summary_id ()] : NULL;
> }
>
> + using function_summary_base<T>::remove;
> + void remove (cgraph_node *node)
> + {
> + if (exists (node))
> + {
> + int id = node->get_summary_id ();
> + this->release ((*m_vector)[id]);
> + (*m_vector)[id] = NULL;
> + }
> + }
> +
> + /* Return true if a summary for the given NODE already exists. */
> + bool exists (cgraph_node *node)
> + {
> + int id = node->get_summary_id ();
> + return (id != -1
> + && (unsigned int)id < m_vector->length ()
> + && (*m_vector)[id] != NULL);
> + }
> +
> + /* Symbol insertion hook that is registered to symbol table. */
> + static void symtab_insertion (cgraph_node *node, void *data);
> +
> + /* Symbol removal hook that is registered to symbol table. */
> + static void symtab_removal (cgraph_node *node, void *data);
> +
> + /* Symbol duplication hook that is registered to symbol table. */
> + static void symtab_duplication (cgraph_node *node, cgraph_node *node2,
> + void *data);
> +
> +private:
> + virtual bool is_ggc ();
> +
> + /* Summary is stored in the vector. */
> + vec <T *, V> *m_vector;
> +
> + template <typename U> friend void gt_ggc_mx (fast_function_summary <U *, va_gc> * const &);
> + template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &);
> + template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &,
> + gt_pointer_operator, void *);
> +};
> +
> +template <typename T, typename V>
> +fast_function_summary<T *, V>::fast_function_summary (symbol_table *symtab):
> + function_summary_base<T> (symtab), m_vector (NULL)
> +{
> + vec_alloc (m_vector, 13);
> + this->m_symtab_insertion_hook
> + = this->m_symtab->add_cgraph_insertion_hook (fast_function_summary::symtab_insertion,
> + this);
> + this->m_symtab_removal_hook
> + = this->m_symtab->add_cgraph_removal_hook (fast_function_summary::symtab_removal,
> + this);
> + this->m_symtab_duplication_hook
> + = this->m_symtab->add_cgraph_duplication_hook (fast_function_summary::symtab_duplication,
> + this);
> +}
> +
> +template <typename T, typename V>
> +void
> +fast_function_summary<T *, V>::release ()
> +{
> + if (this->m_released)
> + return;
> +
> + this->unregister_hooks ();
> +
> + /* Release all summaries. */
> + for (unsigned i = 0; i < m_vector->length (); i++)
> + if ((*m_vector)[i] != NULL)
> + this->release ((*m_vector)[i]);
> +
> + this->m_released = true;
> +}
> +
> +template <typename T, typename V>
> +void
> +fast_function_summary<T *, V>::symtab_insertion (cgraph_node *node, void *data)
> +{
> + gcc_checking_assert (node->get_uid ());
> + fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
> +
> + if (summary->m_insertion_enabled)
> + summary->insert (node, summary->get_create (node));
> +}
> +
> +template <typename T, typename V>
> +void
> +fast_function_summary<T *, V>::symtab_removal (cgraph_node *node, void *data)
> +{
> + gcc_checking_assert (node->get_uid ());
> + fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
> +
> + if (summary->exists (node))
> + summary->remove (node);
> +}
> +
> +template <typename T, typename V>
> +void
> +fast_function_summary<T *, V>::symtab_duplication (cgraph_node *node,
> + cgraph_node *node2,
> + void *data)
> +{
> + fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
> + T *v = summary->get (node);
> +
> + if (v)
> + {
> + T *duplicate = summary->get_create (node2);
> + summary->duplicate (node, node2, v, duplicate);
> + }
> +}
> +
> +template <typename T, typename V>
> +inline bool
> +fast_function_summary<T *, V>::is_ggc ()
> +{
> + return is_same<V, va_gc>::value;
> +}
> +
> +template <typename T>
> +void
> +gt_ggc_mx (fast_function_summary<T *, va_heap>* const &)
> +{
> +}
> +
> +template <typename T>
> +void
> +gt_pch_nx (fast_function_summary<T *, va_heap>* const &)
> +{
> +}
> +
> +template <typename T>
> +void
> +gt_pch_nx (fast_function_summary<T *, va_heap>* const&, gt_pointer_operator,
> + void *)
> +{
> +}
> +
> +template <typename T>
> +void
> +gt_ggc_mx (fast_function_summary<T *, va_gc>* const &summary)
> +{
> + ggc_test_and_set_mark (summary->m_vector);
> + gt_ggc_mx (summary->m_vector);
> +}
> +
> +template <typename T>
> +void
> +gt_pch_nx (fast_function_summary<T *, va_gc>* const &summary)
> +{
> + gt_pch_nx (summary->m_vector);
> +}
> +
> +template <typename T>
> +void
> +gt_pch_nx (fast_function_summary<T *, va_gc>* const& summary,
> + gt_pointer_operator op,
> + void *cookie)
> +{
> + gt_pch_nx (summary->m_vector, op, cookie);
> +}
> +
> +/* Base class for call_summary and fast_call_summary classes. */
> +
> +template <class T>
> +class call_summary_base
> +{
> +public:
> + /* Default construction takes SYMTAB as an argument. */
> + call_summary_base (symbol_table *symtab): m_symtab (symtab),
> + m_initialize_when_cloning (true), m_released (false)
> + {}
> +
> /* Basic implementation of removal operation. */
> virtual void remove (cgraph_edge *, T *) {}
>
> /* Basic implementation of duplication operation. */
> virtual void duplicate (cgraph_edge *, cgraph_edge *, T *, T *) {}
>
> +protected:
> /* Allocates new data that are stored within map. */
> T* allocate_new ()
> {
> /* Call gcc_internal_because we do not want to call finalizer for
> a type T. We call dtor explicitly. */
> - return m_ggc ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
> + return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
> }
>
> /* Release an item that is stored within map. */
> - void release (T *item);
> + void release (T *item)
> + {
> + if (is_ggc ())
> + {
> + item->~T ();
> + ggc_free (item);
> + }
> + else
> + delete item;
> + }
> +
> + /* Unregister all call-graph hooks. */
> + void unregister_hooks ();
> +
> + /* Symbol table the summary is registered to. */
> + symbol_table *m_symtab;
> +
> + /* Internal summary removal hook pointer. */
> + cgraph_edge_hook_list *m_symtab_removal_hook;
> + /* Internal summary duplication hook pointer. */
> + cgraph_2edge_hook_list *m_symtab_duplication_hook;
> + /* Initialize summary for an edge that is cloned. */
> + bool m_initialize_when_cloning;
> + /* Indicates if the summary is released. */
> + bool m_released;
> +
> +private:
> + /* Return true when the summary uses GGC memory for allocation. */
> + virtual bool is_ggc () = 0;
> +};
> +
> +template <typename T>
> +void
> +call_summary_base<T>::unregister_hooks ()
> +{
> + m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
> + m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
> +}
> +
> +/* An impossible class templated by non-pointers so, which makes sure that only
> + summaries gathering pointers can be created. */
> +
> +template <class T>
> +class call_summary
> +{
> +private:
> + call_summary ();
> +};
> +
> +/* Class to store auxiliary information about call graph edges. */
> +
> +template <class T>
> +class GTY((user)) call_summary <T *>: public call_summary_base<T>
> +{
> +public:
> + /* Default construction takes SYMTAB as an argument. */
> + call_summary (symbol_table *symtab, bool ggc = false)
> + : call_summary_base<T> (symtab), m_ggc (ggc), m_map (13, ggc)
> + {
> + this->m_symtab_removal_hook
> + = this->m_symtab->add_edge_removal_hook (call_summary::symtab_removal,
> + this);
> + this->m_symtab_duplication_hook
> + = this->m_symtab->add_edge_duplication_hook (call_summary::symtab_duplication,
> + this);
> + }
> +
> + /* Destructor. */
> + virtual ~call_summary ()
> + {
> + release ();
> + }
> +
> + /* Destruction method that can be called for GGC purpose. */
> + using call_summary_base<T>::release;
> + void release ();
> +
> + /* Traverses all summarys with an edge E called with
> + ARG as argument. */
> + template<typename Arg, bool (*f)(const T &, Arg)>
> + void traverse (Arg a) const
> + {
> + m_map.traverse <f> (a);
> + }
>
> /* Getter for summary callgraph edge pointer.
> If a summary for an edge does not exist, it will be created. */
> @@ -371,7 +671,7 @@ public:
> bool existed;
> T **v = &m_map.get_or_insert (edge->get_uid (), &existed);
> if (!existed)
> - *v = allocate_new ();
> + *v = this->allocate_new ();
>
> return *v;
> }
> @@ -384,6 +684,7 @@ public:
> }
>
> /* Remove edge from summary. */
> + using call_summary_base<T>::remove;
> void remove (cgraph_edge *edge)
> {
> int uid = edge->get_uid ();
> @@ -391,16 +692,10 @@ public:
> if (v)
> {
> m_map.remove (uid);
> - release (*v);
> + this->release (*v);
> }
> }
>
> - /* Return number of elements handled by data structure. */
> - size_t elements ()
> - {
> - return m_map.elements ();
> - }
> -
> /* Return true if a summary for the given EDGE already exists. */
> bool exists (cgraph_edge *edge)
> {
> @@ -418,22 +713,17 @@ protected:
> /* Indication if we use ggc summary. */
> bool m_ggc;
>
> - /* Initialize summary for an edge that is cloned. */
> - bool m_initialize_when_cloning;
> -
> private:
> + /* Indication if we use ggc summary. */
> + virtual bool is_ggc ()
> + {
> + return m_ggc;
> + }
> +
> typedef int_hash <int, 0, -1> map_hash;
>
> /* Main summary store, where summary ID is used as key. */
> hash_map <map_hash, T *> m_map;
> - /* Internal summary removal hook pointer. */
> - cgraph_edge_hook_list *m_symtab_removal_hook;
> - /* Internal summary duplication hook pointer. */
> - cgraph_2edge_hook_list *m_symtab_duplication_hook;
> - /* Indicates if the summary is released. */
> - bool m_released;
> - /* Symbol table the summary is registered to. */
> - symbol_table *m_symtab;
>
> template <typename U> friend void gt_ggc_mx (call_summary <U *> * const &);
> template <typename U> friend void gt_pch_nx (call_summary <U *> * const &);
> @@ -445,31 +735,17 @@ template <typename T>
> void
> call_summary<T *>::release ()
> {
> - if (m_released)
> + if (this->m_released)
> return;
>
> - m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
> - m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
> + this->unregister_hooks ();
>
> /* Release all summaries. */
> typedef typename hash_map <map_hash, T *>::iterator map_iterator;
> for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
> - release ((*it).second);
> + this->release ((*it).second);
>
> - m_released = true;
> -}
> -
> -template <typename T>
> -void
> -call_summary<T *>::release (T *item)
> -{
> - if (m_ggc)
> - {
> - item->~T ();
> - ggc_free (item);
> - }
> - else
> - delete item;
> + this->m_released = true;
> }
>
> template <typename T>
> @@ -477,16 +753,7 @@ void
> call_summary<T *>::symtab_removal (cgraph_edge *edge, void *data)
> {
> call_summary *summary = (call_summary <T *> *) (data);
> -
> - int h_uid = edge->get_uid ();
> - T **v = summary->m_map.get (h_uid);
> -
> - if (v)
> - {
> - summary->remove (edge, *v);
> - summary->release (*v);
> - summary->m_map.remove (h_uid);
> - }
> + summary->remove (edge);
> }
>
> template <typename T>
> @@ -500,21 +767,11 @@ call_summary<T *>::symtab_duplication (cgraph_edge *edge1,
> if (summary->m_initialize_when_cloning)
> edge1_summary = summary->get_create (edge1);
> else
> - {
> - T **v = summary->m_map.get (edge1->get_uid ());
> - if (v)
> - {
> - /* This load is necessary, because we insert a new value! */
> - edge1_summary = *v;
> - }
> - }
> + edge1_summary = summary->get (edge1);
>
> if (edge1_summary)
> - {
> - T *duplicate = summary->allocate_new ();
> - summary->m_map.put (edge2->get_uid (), duplicate);
> - summary->duplicate (edge1, edge2, edge1_summary, duplicate);
> - }
> + summary->duplicate (edge1, edge2, edge1_summary,
> + summary->get_create (edge2));
> }
>
> template <typename T>
> @@ -542,4 +799,213 @@ gt_pch_nx(call_summary<T *>* const& summary, gt_pointer_operator op,
> gt_pch_nx (&summary->m_map, op, cookie);
> }
>
> +/* We want to pass just pointer types as argument for fast_call_summary
> + template class. */
> +
> +template <class T, class V>
> +class fast_call_summary
> +{
> +private:
> + fast_call_summary ();
> +};
> +
> +/* Call vector summary is a fast implementation of call_summary that
> + utilizes vector as primary storage of summaries. */
> +
> +template <class T, class V>
> +class GTY((user)) fast_call_summary <T *, V>: public call_summary_base<T>
> +{
> +public:
> + /* Default construction takes SYMTAB as an argument. */
> + fast_call_summary (symbol_table *symtab)
> + : call_summary_base<T> (symtab), m_vector (NULL)
> + {
> + vec_alloc (m_vector, 13);
> + this->m_symtab_removal_hook
> + = this->m_symtab->add_edge_removal_hook (fast_call_summary::symtab_removal,
> + this);
> + this->m_symtab_duplication_hook
> + = this->m_symtab->add_edge_duplication_hook (fast_call_summary::symtab_duplication,
> + this);
> + }
> +
> + /* Destructor. */
> + virtual ~fast_call_summary ()
> + {
> + release ();
> + }
> +
> + /* Destruction method that can be called for GGC purpose. */
> + using call_summary_base<T>::release;
> + void release ();
> +
> + /* Traverses all summarys with an edge F called with
> + ARG as argument. */
> + template<typename Arg, bool (*f)(const T &, Arg)>
> + void traverse (Arg a) const
> + {
> + for (unsigned i = 0; i < m_vector->length (); i++)
> + if ((*m_vector[i]) != NULL)
> + f ((*m_vector)[i]);
> + }
> +
> + /* Getter for summary callgraph edge pointer.
> + If a summary for an edge does not exist, it will be created. */
> + T* get_create (cgraph_edge *edge)
> + {
> + int id = edge->get_summary_id ();
> + if (id == -1)
> + id = this->m_symtab->assign_summary_id (edge);
> +
> + if ((unsigned)id >= m_vector->length ())
> + vec_safe_grow_cleared (m_vector, this->m_symtab->edges_max_summary_id);
> +
> + if ((*m_vector)[id] == NULL)
> + (*m_vector)[id] = this->allocate_new ();
> +
> + return (*m_vector)[id];
> + }
> +
> + /* Getter for summary callgraph edge pointer. */
> + T* get (cgraph_edge *edge) ATTRIBUTE_PURE
> + {
> + return exists (edge) ? (*m_vector)[edge->get_summary_id ()] : NULL;
> + }
> +
> + /* Remove edge from summary. */
> + using call_summary_base<T>::remove;
> + void remove (cgraph_edge *edge)
> + {
> + if (exists (edge))
> + {
> + int id = edge->get_summary_id ();
> + this->release ((*m_vector)[id]);
> + (*m_vector)[id] = NULL;
> + }
> + }
> +
> + /* Return true if a summary for the given EDGE already exists. */
> + bool exists (cgraph_edge *edge)
> + {
> + int id = edge->get_summary_id ();
> + return (id != -1
> + && (unsigned)id < m_vector->length ()
> + && (*m_vector)[id] != NULL);
> + }
> +
> + /* Symbol removal hook that is registered to symbol table. */
> + static void symtab_removal (cgraph_edge *edge, void *data);
> +
> + /* Symbol duplication hook that is registered to symbol table. */
> + static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2,
> + void *data);
> +
> +private:
> + virtual bool is_ggc ();
> +
> + /* Summary is stored in the vector. */
> + vec <T *, V> *m_vector;
> +
> + template <typename U> friend void gt_ggc_mx (fast_call_summary <U *, va_gc> * const &);
> + template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &);
> + template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &,
> + gt_pointer_operator, void *);
> +};
> +
> +template <typename T, typename V>
> +void
> +fast_call_summary<T *, V>::release ()
> +{
> + if (this->m_released)
> + return;
> +
> + this->unregister_hooks ();
> +
> + /* Release all summaries. */
> + for (unsigned i = 0; i < m_vector->length (); i++)
> + if ((*m_vector)[i] != NULL)
> + this->release ((*m_vector)[i]);
> +
> + this->m_released = true;
> +}
> +
> +template <typename T, typename V>
> +void
> +fast_call_summary<T *, V>::symtab_removal (cgraph_edge *edge, void *data)
> +{
> + fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
> + summary->remove (edge);
> +}
> +
> +template <typename T, typename V>
> +void
> +fast_call_summary<T *, V>::symtab_duplication (cgraph_edge *edge1,
> + cgraph_edge *edge2, void *data)
> +{
> + fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
> + T *edge1_summary = NULL;
> +
> + if (summary->m_initialize_when_cloning)
> + edge1_summary = summary->get_create (edge1);
> + else
> + edge1_summary = summary->get (edge1);
> +
> + if (edge1_summary)
> + {
> + T *duplicate = summary->get_create (edge2);
> + summary->duplicate (edge1, edge2, edge1_summary, duplicate);
> + }
> +}
> +
> +template <typename T, typename V>
> +inline bool
> +fast_call_summary<T *, V>::is_ggc ()
> +{
> + return is_same<V, va_gc>::value;
> +}
> +
> +template <typename T>
> +void
> +gt_ggc_mx (fast_call_summary<T *, va_heap>* const &summary)
> +{
> +}
> +
> +template <typename T>
> +void
> +gt_pch_nx (fast_call_summary<T *, va_heap>* const &summary)
> +{
> +}
> +
> +template <typename T>
> +void
> +gt_pch_nx (fast_call_summary<T *, va_heap>* const& summary,
> + gt_pointer_operator op,
> + void *cookie)
> +{
> +}
> +
> +template <typename T>
> +void
> +gt_ggc_mx (fast_call_summary<T *, va_gc>* const &summary)
> +{
> + ggc_test_and_set_mark (summary->m_vector);
> + gt_ggc_mx (&summary->m_vector);
> +}
> +
> +template <typename T>
> +void
> +gt_pch_nx (fast_call_summary<T *, va_gc>* const &summary)
> +{
> + gt_pch_nx (&summary->m_vector);
> +}
> +
> +template <typename T>
> +void
> +gt_pch_nx (fast_call_summary<T *, va_gc>* const& summary,
> + gt_pointer_operator op,
> + void *cookie)
> +{
> + gt_pch_nx (&summary->m_vector, op, cookie);
> +}
> +
> #endif /* GCC_SYMBOL_SUMMARY_H */
> diff --git a/gcc/vec.h b/gcc/vec.h
> index 8c2a39b0b05..4bd9df9aba5 100644
> --- a/gcc/vec.h
> +++ b/gcc/vec.h
> @@ -732,6 +732,17 @@ vec_safe_grow_cleared (vec<T, A, vl_embed> *&v, unsigned len CXX_MEM_STAT_INFO)
> }
>
>
> +/* Assume V is not NULL. */
> +
> +template<typename T>
> +inline void
> +vec_safe_grow_cleared (vec<T, va_heap, vl_ptr> *&v,
> + unsigned len CXX_MEM_STAT_INFO)
> +{
> + v->safe_grow_cleared (len);
> +}
> +
> +
> /* If V is NULL return false, otherwise return V->iterate(IX, PTR). */
> template<typename T, typename A>
> inline bool
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2019-02-18 8:09 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-15 11:42 [PATCH] Come up with fast {function,call}_summary classes (PR ipa/89306) Martin Liška
2019-02-15 12:09 ` Martin Liška
2019-02-18 8:09 ` Jan Hubicka
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).