| /* Callgraph summary data structure. |
| Copyright (C) 2014-2022 Free Software Foundation, Inc. |
| Contributed by Martin Liska |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #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, |
| cgraph_node_hook symtab_insertion, |
| cgraph_node_hook symtab_removal, |
| cgraph_2node_hook symtab_duplication |
| CXX_MEM_STAT_INFO): |
| m_symtab (symtab), m_symtab_insertion (symtab_insertion), |
| m_symtab_removal (symtab_removal), |
| m_symtab_duplication (symtab_duplication), |
| m_symtab_insertion_hook (NULL), m_symtab_duplication_hook (NULL), |
| m_allocator ("function summary" PASS_MEM_STAT) |
| { |
| enable_insertion_hook (); |
| m_symtab_removal_hook |
| = m_symtab->add_cgraph_removal_hook (m_symtab_removal, this); |
| enable_duplication_hook (); |
| } |
| |
| /* Basic implementation of insert operation. */ |
| virtual void insert (cgraph_node *, T *) |
| { |
| /* In most cases, it makes no sense to create summaries without |
| initializing them. */ |
| gcc_unreachable (); |
| } |
| |
| /* 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 *) |
| { |
| /* It makes no sense to not copy anything during duplication. */ |
| gcc_unreachable (); |
| } |
| |
| /* Enable insertion hook invocation. */ |
| void enable_insertion_hook () |
| { |
| if (m_symtab_insertion_hook == NULL) |
| m_symtab_insertion_hook |
| = m_symtab->add_cgraph_insertion_hook (m_symtab_insertion, this); |
| } |
| |
| /* Enable insertion hook invocation. */ |
| void disable_insertion_hook () |
| { |
| if (m_symtab_insertion_hook != NULL) |
| { |
| m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook); |
| m_symtab_insertion_hook = NULL; |
| } |
| } |
| |
| /* Enable duplication hook invocation. */ |
| void enable_duplication_hook () |
| { |
| if (m_symtab_duplication_hook == NULL) |
| m_symtab_duplication_hook |
| = m_symtab->add_cgraph_duplication_hook (m_symtab_duplication, this); |
| } |
| |
| /* Enable duplication hook invocation. */ |
| void disable_duplication_hook () |
| { |
| if (m_symtab_duplication_hook != NULL) |
| { |
| m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook); |
| m_symtab_duplication_hook = NULL; |
| } |
| } |
| |
| 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 () |
| : m_allocator.allocate () ; |
| } |
| |
| /* Release an item that is stored within map. */ |
| void release (T *item) |
| { |
| if (is_ggc ()) |
| ggc_delete (item); |
| else |
| m_allocator.remove (item); |
| } |
| |
| /* Unregister all call-graph hooks. */ |
| void unregister_hooks (); |
| |
| /* Symbol table the summary is registered to. */ |
| symbol_table *m_symtab; |
| |
| /* Insertion function defined by a summary. */ |
| cgraph_node_hook m_symtab_insertion; |
| /* Removal function defined by a summary. */ |
| cgraph_node_hook m_symtab_removal; |
| /* Duplication function defined by a summary. */ |
| cgraph_2node_hook m_symtab_duplication; |
| |
| /* 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; |
| |
| private: |
| /* Return true when the summary uses GGC memory for allocation. */ |
| virtual bool is_ggc () = 0; |
| |
| /* Object allocator for heap allocation. */ |
| object_allocator<T> m_allocator; |
| }; |
| |
| template <typename T> |
| void |
| function_summary_base<T>::unregister_hooks () |
| { |
| disable_insertion_hook (); |
| m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook); |
| disable_duplication_hook (); |
| } |
| |
| /* We want to pass just pointer types as argument for function_summary |
| template class. */ |
| |
| template <class T> |
| class function_summary |
| { |
| private: |
| function_summary(); |
| }; |
| |
| /* Function summary is a helper class that is used to associate a data structure |
| related to a callgraph node. Typical usage can be seen in IPA passes which |
| create a temporary pass-related structures. The summary class registers |
| hooks that are triggered when a new node is inserted, duplicated and deleted. |
| A user of a summary class can ovewrite virtual methods than are triggered by |
| the summary if such hook is triggered. Apart from a callgraph node, the user |
| is given a data structure tied to the node. |
| |
| The function summary class can work both with a heap-allocated memory and |
| a memory gained by garbage collected memory. */ |
| |
| template <class T> |
| class GTY((user)) function_summary <T *>: public function_summary_base<T> |
| { |
| public: |
| /* Default construction takes SYMTAB as an argument. */ |
| function_summary (symbol_table *symtab, bool ggc = false CXX_MEM_STAT_INFO); |
| |
| /* Destructor. */ |
| virtual ~function_summary (); |
| |
| /* Traverses all summarys with a function F called with |
| ARG as argument. */ |
| template<typename Arg, bool (*f)(const T &, Arg)> |
| void traverse (Arg a) const |
| { |
| m_map.template traverse <f> (a); |
| } |
| |
| /* 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) |
| { |
| bool existed; |
| T **v = &m_map.get_or_insert (node->get_uid (), &existed); |
| if (!existed) |
| *v = this->allocate_new (); |
| |
| return *v; |
| } |
| |
| /* Getter for summary callgraph node pointer. */ |
| T* get (cgraph_node *node) ATTRIBUTE_PURE |
| { |
| T **v = m_map.get (node->get_uid ()); |
| return v == NULL ? NULL : *v; |
| } |
| |
| /* Remove node from summary. */ |
| using function_summary_base<T>::remove; |
| void remove (cgraph_node *node) |
| { |
| int uid = node->get_uid (); |
| T **v = m_map.get (uid); |
| if (v) |
| { |
| m_map.remove (uid); |
| this->release (*v); |
| } |
| } |
| |
| /* Return true if a summary for the given NODE already exists. */ |
| bool exists (cgraph_node *node) |
| { |
| return m_map.get (node->get_uid ()) != 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); |
| |
| protected: |
| /* Indication if we use ggc summary. */ |
| 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; |
| |
| /* Main summary store, where summary ID is used as key. */ |
| hash_map <map_hash, T *> m_map; |
| |
| template <typename U> friend void gt_ggc_mx (function_summary <U *> * const &); |
| template <typename U> friend void gt_pch_nx (function_summary <U *> * const &); |
| template <typename U> friend void gt_pch_nx (function_summary <U *> * const &, |
| gt_pointer_operator, void *); |
| }; |
| |
| template <typename T> |
| function_summary<T *>::function_summary (symbol_table *symtab, bool ggc |
| MEM_STAT_DECL): |
| function_summary_base<T> (symtab, function_summary::symtab_insertion, |
| function_summary::symtab_removal, |
| function_summary::symtab_duplication |
| PASS_MEM_STAT), |
| m_ggc (ggc), m_map (13, ggc, true, GATHER_STATISTICS PASS_MEM_STAT) {} |
| |
| template <typename T> |
| function_summary<T *>::~function_summary () |
| { |
| 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) |
| this->release ((*it).second); |
| } |
| |
| template <typename T> |
| void |
| function_summary<T *>::symtab_insertion (cgraph_node *node, void *data) |
| { |
| gcc_checking_assert (node->get_uid ()); |
| function_summary *summary = (function_summary <T *> *) (data); |
| summary->insert (node, summary->get_create (node)); |
| } |
| |
| template <typename T> |
| void |
| function_summary<T *>::symtab_removal (cgraph_node *node, void *data) |
| { |
| gcc_checking_assert (node->get_uid ()); |
| function_summary *summary = (function_summary <T *> *) (data); |
| summary->remove (node); |
| } |
| |
| template <typename T> |
| void |
| function_summary<T *>::symtab_duplication (cgraph_node *node, |
| cgraph_node *node2, void *data) |
| { |
| function_summary *summary = (function_summary <T *> *) (data); |
| T *v = summary->get (node); |
| |
| if (v) |
| summary->duplicate (node, node2, v, summary->get_create (node2)); |
| } |
| |
| template <typename T> |
| void |
| gt_ggc_mx(function_summary<T *>* const &summary) |
| { |
| gcc_checking_assert (summary->m_ggc); |
| gt_ggc_mx (&summary->m_map); |
| } |
| |
| template <typename T> |
| void |
| gt_pch_nx (function_summary<T *> *const &) |
| { |
| gcc_unreachable (); |
| } |
| |
| template <typename T> |
| void |
| gt_pch_nx (function_summary<T *> *const &, gt_pointer_operator, void *) |
| { |
| gcc_unreachable (); |
| } |
| |
| /* Help template from std c++11. */ |
| |
| 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: |
| fast_function_summary (); |
| }; |
| |
| /* Function vector summary is a fast implementation of function_summary that |
| utilizes vector as primary storage of summaries. */ |
| |
| 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. */ |
| fast_function_summary (symbol_table *symtab CXX_MEM_STAT_INFO); |
| |
| /* Destructor. */ |
| virtual ~fast_function_summary (); |
| |
| /* Traverses all summarys with a function 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], a); |
| } |
| |
| /* 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 |
| MEM_STAT_DECL): |
| function_summary_base<T> (symtab, |
| fast_function_summary::symtab_insertion, |
| fast_function_summary::symtab_removal, |
| fast_function_summary::symtab_duplication |
| PASS_MEM_STAT), m_vector (NULL) |
| { |
| vec_alloc (m_vector, 13 PASS_MEM_STAT); |
| } |
| |
| template <typename T, typename V> |
| fast_function_summary<T *, V>::~fast_function_summary () |
| { |
| 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]); |
| vec_free (m_vector); |
| } |
| |
| 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); |
| 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 &) |
| { |
| gcc_unreachable (); |
| } |
| |
| template <typename T> |
| void |
| gt_pch_nx (fast_function_summary<T *, va_gc> *const &, gt_pointer_operator, |
| void *) |
| { |
| gcc_unreachable (); |
| } |
| |
| /* 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, cgraph_edge_hook symtab_removal, |
| cgraph_2edge_hook symtab_duplication CXX_MEM_STAT_INFO): |
| m_symtab (symtab), m_symtab_removal (symtab_removal), |
| m_symtab_duplication (symtab_duplication), m_symtab_duplication_hook (NULL), |
| m_initialize_when_cloning (false), |
| m_allocator ("call summary" PASS_MEM_STAT) |
| { |
| m_symtab_removal_hook |
| = m_symtab->add_edge_removal_hook (m_symtab_removal, this); |
| enable_duplication_hook (); |
| } |
| |
| /* 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 *) |
| { |
| gcc_unreachable (); |
| } |
| |
| /* Enable duplication hook invocation. */ |
| void enable_duplication_hook () |
| { |
| if (m_symtab_duplication_hook == NULL) |
| m_symtab_duplication_hook |
| = m_symtab->add_edge_duplication_hook (m_symtab_duplication, |
| this); |
| } |
| |
| /* Enable duplication hook invocation. */ |
| void disable_duplication_hook () |
| { |
| if (m_symtab_duplication_hook != NULL) |
| { |
| m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook); |
| m_symtab_duplication_hook = NULL; |
| } |
| } |
| |
| 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 () |
| : m_allocator.allocate (); |
| } |
| |
| /* Release an item that is stored within map. */ |
| void release (T *item) |
| { |
| if (is_ggc ()) |
| ggc_delete (item); |
| else |
| m_allocator.remove (item); |
| } |
| |
| /* Unregister all call-graph hooks. */ |
| void unregister_hooks (); |
| |
| /* Symbol table the summary is registered to. */ |
| symbol_table *m_symtab; |
| |
| /* Removal function defined by a summary. */ |
| cgraph_edge_hook m_symtab_removal; |
| /* Duplication function defined by a summary. */ |
| cgraph_2edge_hook m_symtab_duplication; |
| |
| /* 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; |
| |
| private: |
| /* Return true when the summary uses GGC memory for allocation. */ |
| virtual bool is_ggc () = 0; |
| |
| /* Object allocator for heap allocation. */ |
| object_allocator<T> m_allocator; |
| }; |
| |
| template <typename T> |
| void |
| call_summary_base<T>::unregister_hooks () |
| { |
| m_symtab->remove_edge_removal_hook (m_symtab_removal_hook); |
| disable_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 |
| CXX_MEM_STAT_INFO) |
| : call_summary_base<T> (symtab, call_summary::symtab_removal, |
| call_summary::symtab_duplication PASS_MEM_STAT), |
| m_ggc (ggc), m_map (13, ggc, true, GATHER_STATISTICS PASS_MEM_STAT) {} |
| |
| /* Destructor. */ |
| virtual ~call_summary (); |
| |
| /* 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.template traverse <f> (a); |
| } |
| |
| /* 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) |
| { |
| bool existed; |
| T **v = &m_map.get_or_insert (edge->get_uid (), &existed); |
| if (!existed) |
| *v = this->allocate_new (); |
| |
| return *v; |
| } |
| |
| /* Getter for summary callgraph edge pointer. */ |
| T* get (cgraph_edge *edge) ATTRIBUTE_PURE |
| { |
| T **v = m_map.get (edge->get_uid ()); |
| return v == NULL ? NULL : *v; |
| } |
| |
| /* Remove edge from summary. */ |
| using call_summary_base<T>::remove; |
| void remove (cgraph_edge *edge) |
| { |
| int uid = edge->get_uid (); |
| T **v = m_map.get (uid); |
| if (v) |
| { |
| m_map.remove (uid); |
| this->release (*v); |
| } |
| } |
| |
| /* Return true if a summary for the given EDGE already exists. */ |
| bool exists (cgraph_edge *edge) |
| { |
| return m_map.get (edge->get_uid ()) != 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); |
| |
| protected: |
| /* Indication if we use ggc summary. */ |
| 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; |
| |
| /* Main summary store, where summary ID is used as key. */ |
| hash_map <map_hash, T *> m_map; |
| |
| template <typename U> friend void gt_ggc_mx (call_summary <U *> * const &); |
| template <typename U> friend void gt_pch_nx (call_summary <U *> * const &); |
| template <typename U> friend void gt_pch_nx (call_summary <U *> * const &, |
| gt_pointer_operator, void *); |
| }; |
| |
| template <typename T> |
| call_summary<T *>::~call_summary () |
| { |
| 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) |
| this->release ((*it).second); |
| } |
| |
| template <typename T> |
| void |
| call_summary<T *>::symtab_removal (cgraph_edge *edge, void *data) |
| { |
| call_summary *summary = (call_summary <T *> *) (data); |
| summary->remove (edge); |
| } |
| |
| template <typename T> |
| void |
| call_summary<T *>::symtab_duplication (cgraph_edge *edge1, |
| cgraph_edge *edge2, void *data) |
| { |
| call_summary *summary = (call_summary <T *> *) (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) |
| summary->duplicate (edge1, edge2, edge1_summary, |
| summary->get_create (edge2)); |
| } |
| |
| template <typename T> |
| void |
| gt_ggc_mx(call_summary<T *>* const &summary) |
| { |
| gcc_checking_assert (summary->m_ggc); |
| gt_ggc_mx (&summary->m_map); |
| } |
| |
| template <typename T> |
| void |
| gt_pch_nx (call_summary<T *> *const &) |
| { |
| gcc_unreachable (); |
| } |
| |
| template <typename T> |
| void |
| gt_pch_nx (call_summary<T *> *const &, gt_pointer_operator, void *) |
| { |
| gcc_unreachable (); |
| } |
| |
| /* 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 CXX_MEM_STAT_INFO) |
| : call_summary_base<T> (symtab, fast_call_summary::symtab_removal, |
| fast_call_summary::symtab_duplication PASS_MEM_STAT), |
| m_vector (NULL) |
| { |
| vec_alloc (m_vector, 13 PASS_MEM_STAT); |
| } |
| |
| /* Destructor. */ |
| virtual ~fast_call_summary (); |
| |
| /* 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], a); |
| } |
| |
| /* 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> |
| fast_call_summary<T *, V>::~fast_call_summary () |
| { |
| 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]); |
| vec_free (m_vector); |
| } |
| |
| 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 ATTRIBUTE_UNUSED) |
| { |
| } |
| |
| template <typename T> |
| void |
| gt_pch_nx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED) |
| { |
| } |
| |
| template <typename T> |
| void |
| gt_pch_nx (fast_call_summary<T *, va_heap>* const& summary ATTRIBUTE_UNUSED, |
| gt_pointer_operator op ATTRIBUTE_UNUSED, |
| void *cookie ATTRIBUTE_UNUSED) |
| { |
| } |
| |
| 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 &) |
| { |
| gcc_unreachable (); |
| } |
| |
| template <typename T> |
| void |
| gt_pch_nx (fast_call_summary<T *, va_gc> *const &, gt_pointer_operator, void *) |
| { |
| gcc_unreachable (); |
| } |
| |
| #endif /* GCC_SYMBOL_SUMMARY_H */ |