From db30281f0b2ff6dfc0c4146291baf020a27e4065 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Mon, 18 Feb 2019 09:21:23 +0100 Subject: [PATCH] Come up with fast {function,call}_summary classes (PR ipa/89306). 2019-02-18 Martin Liska 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. From-SVN: r268979 --- gcc/ChangeLog | 30 ++ 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 + 9 files changed, 765 insertions(+), 211 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a200aac3434..9370f013f07 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,33 @@ +2019-02-18 Martin Liska + + 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. + 2019-02-18 Martin Liska * config/i386/i386.c (ix86_get_multilib_abi_name): New function. 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 (); + { + edge = ggc_alloc (); + 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 (); + { + node = ggc_cleared_alloc (); + 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_summaries; -call_summary *ipa_call_summaries; +fast_function_summary *ipa_fn_summaries; +fast_call_summary *ipa_call_summaries; /* Edge predicates goes here. */ static object_allocator 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 +class GTY((user)) ipa_fn_summary_t: + public fast_function_summary { public: - ipa_fn_summary_t (symbol_table *symtab, bool ggc): - function_summary (symtab, ggc) {} + ipa_fn_summary_t (symbol_table *symtab): + fast_function_summary (symtab) {} static ipa_fn_summary_t *create_ggc (symbol_table *symtab) { struct ipa_fn_summary_t *summary = new (ggc_alloc ()) - 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_summaries; +extern GTY(()) fast_function_summary + *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 +class ipa_call_summary_t: public fast_call_summary { public: - ipa_call_summary_t (symbol_table *symtab, bool ggc): - call_summary (symtab, ggc) {} + ipa_call_summary_t (symbol_table *symtab): + fast_call_summary (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_summaries; +extern fast_call_summary *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 +class funct_state_summary_t: + public fast_function_summary { public: funct_state_summary_t (symbol_table *symtab): - function_summary (symtab) {} + fast_function_summary (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 - +class ipa_ref_var_info_summary_t: public fast_function_summary + { public: ipa_ref_var_info_summary_t (symbol_table *symtab): - function_summary (symtab) {} + fast_function_summary (symtab) {} }; static ipa_ref_var_info_summary_t *ipa_ref_var_info_summaries = NULL; -class ipa_ref_opt_summary_t: public function_summary - +class ipa_ref_opt_summary_t: public fast_function_summary + { public: ipa_ref_opt_summary_t (symbol_table *symtab): - function_summary (symtab) {} - + fast_function_summary (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 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 +void +function_summary_base::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 GTY((user)) function_summary +class GTY((user)) function_summary : public function_summary_base { 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::release; void release (); /* Traverses all summarys with a function F called with @@ -66,26 +151,6 @@ public: m_map.traverse (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::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 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 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 friend void gt_ggc_mx (function_summary * const &); template friend void gt_pch_nx (function_summary * const &); @@ -181,50 +223,34 @@ private: template function_summary::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 (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 void function_summary::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 ::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 -void -function_summary::release (T *item) -{ - if (m_ggc) - { - item->~T (); - ggc_free (item); - } - else - delete item; + this->m_released = true; } template @@ -244,19 +270,7 @@ function_summary::symtab_removal (cgraph_node *node, void *data) { gcc_checking_assert (node->get_uid ()); function_summary *summary = (function_summary *) (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 @@ -268,12 +282,7 @@ function_summary::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 @@ -301,42 +310,49 @@ gt_pch_nx(function_summary* 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 call_summary +template +struct is_same +{ + static const bool value = false; +}; + +template +struct is_same //specialization +{ + static const bool value = true; +}; + +/* We want to pass just pointer types as argument for fast_function_summary + template class. */ + +template +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 GTY((user)) call_summary +template +class GTY((user)) fast_function_summary + : public function_summary_base { 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::release; void release (); /* Traverses all summarys with a function F called with @@ -344,25 +360,309 @@ public: template void traverse (Arg a) const { - m_map.traverse (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::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 *m_vector; + + template friend void gt_ggc_mx (fast_function_summary * const &); + template friend void gt_pch_nx (fast_function_summary * const &); + template friend void gt_pch_nx (fast_function_summary * const &, + gt_pointer_operator, void *); +}; + +template +fast_function_summary::fast_function_summary (symbol_table *symtab): + function_summary_base (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 +void +fast_function_summary::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 +void +fast_function_summary::symtab_insertion (cgraph_node *node, void *data) +{ + gcc_checking_assert (node->get_uid ()); + fast_function_summary *summary = (fast_function_summary *) (data); + + if (summary->m_insertion_enabled) + summary->insert (node, summary->get_create (node)); +} + +template +void +fast_function_summary::symtab_removal (cgraph_node *node, void *data) +{ + gcc_checking_assert (node->get_uid ()); + fast_function_summary *summary = (fast_function_summary *) (data); + + if (summary->exists (node)) + summary->remove (node); +} + +template +void +fast_function_summary::symtab_duplication (cgraph_node *node, + cgraph_node *node2, + void *data) +{ + fast_function_summary *summary = (fast_function_summary *) (data); + T *v = summary->get (node); + + if (v) + { + T *duplicate = summary->get_create (node2); + summary->duplicate (node, node2, v, duplicate); + } +} + +template +inline bool +fast_function_summary::is_ggc () +{ + return is_same::value; +} + +template +void +gt_ggc_mx (fast_function_summary* const &) +{ +} + +template +void +gt_pch_nx (fast_function_summary* const &) +{ +} + +template +void +gt_pch_nx (fast_function_summary* const&, gt_pointer_operator, + void *) +{ +} + +template +void +gt_ggc_mx (fast_function_summary* const &summary) +{ + ggc_test_and_set_mark (summary->m_vector); + gt_ggc_mx (summary->m_vector); +} + +template +void +gt_pch_nx (fast_function_summary* const &summary) +{ + gt_pch_nx (summary->m_vector); +} + +template +void +gt_pch_nx (fast_function_summary* 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 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 +void +call_summary_base::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 call_summary +{ +private: + call_summary (); +}; + +/* Class to store auxiliary information about call graph edges. */ + +template +class GTY((user)) call_summary : public call_summary_base +{ +public: + /* Default construction takes SYMTAB as an argument. */ + call_summary (symbol_table *symtab, bool ggc = false) + : call_summary_base (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::release; + void release (); + + /* Traverses all summarys with an edge E called with + ARG as argument. */ + template + void traverse (Arg a) const + { + m_map.traverse (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::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 map_hash; /* Main summary store, where summary ID is used as key. */ hash_map 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 friend void gt_ggc_mx (call_summary * const &); template friend void gt_pch_nx (call_summary * const &); @@ -445,31 +735,17 @@ template void call_summary::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 ::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 -void -call_summary::release (T *item) -{ - if (m_ggc) - { - item->~T (); - ggc_free (item); - } - else - delete item; + this->m_released = true; } template @@ -477,16 +753,7 @@ void call_summary::symtab_removal (cgraph_edge *edge, void *data) { call_summary *summary = (call_summary *) (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 @@ -500,21 +767,11 @@ call_summary::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 @@ -542,4 +799,213 @@ gt_pch_nx(call_summary* 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 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 GTY((user)) fast_call_summary : public call_summary_base +{ +public: + /* Default construction takes SYMTAB as an argument. */ + fast_call_summary (symbol_table *symtab) + : call_summary_base (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::release; + void release (); + + /* Traverses all summarys with an edge F called with + ARG as argument. */ + template + 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::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 *m_vector; + + template friend void gt_ggc_mx (fast_call_summary * const &); + template friend void gt_pch_nx (fast_call_summary * const &); + template friend void gt_pch_nx (fast_call_summary * const &, + gt_pointer_operator, void *); +}; + +template +void +fast_call_summary::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 +void +fast_call_summary::symtab_removal (cgraph_edge *edge, void *data) +{ + fast_call_summary *summary = (fast_call_summary *) (data); + summary->remove (edge); +} + +template +void +fast_call_summary::symtab_duplication (cgraph_edge *edge1, + cgraph_edge *edge2, void *data) +{ + fast_call_summary *summary = (fast_call_summary *) (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 +inline bool +fast_call_summary::is_ggc () +{ + return is_same::value; +} + +template +void +gt_ggc_mx (fast_call_summary* const &summary) +{ +} + +template +void +gt_pch_nx (fast_call_summary* const &summary) +{ +} + +template +void +gt_pch_nx (fast_call_summary* const& summary, + gt_pointer_operator op, + void *cookie) +{ +} + +template +void +gt_ggc_mx (fast_call_summary* const &summary) +{ + ggc_test_and_set_mark (summary->m_vector); + gt_ggc_mx (&summary->m_vector); +} + +template +void +gt_pch_nx (fast_call_summary* const &summary) +{ + gt_pch_nx (&summary->m_vector); +} + +template +void +gt_pch_nx (fast_call_summary* 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 *&v, unsigned len CXX_MEM_STAT_INFO) } +/* Assume V is not NULL. */ + +template +inline void +vec_safe_grow_cleared (vec *&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 inline bool -- 2.30.2