Home | History | Annotate | Line # | Download | only in gcc
symbol-summary.h revision 1.1.1.7
      1 /* Callgraph summary data structure.
      2    Copyright (C) 2014-2020 Free Software Foundation, Inc.
      3    Contributed by Martin Liska
      4 
      5 This file is part of GCC.
      6 
      7 GCC is free software; you can redistribute it and/or modify it under
      8 the terms of the GNU General Public License as published by the Free
      9 Software Foundation; either version 3, or (at your option) any later
     10 version.
     11 
     12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15 for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with GCC; see the file COPYING3.  If not see
     19 <http://www.gnu.org/licenses/>.  */
     20 
     21 #ifndef GCC_SYMBOL_SUMMARY_H
     22 #define GCC_SYMBOL_SUMMARY_H
     23 
     24 /* Base class for function_summary and fast_function_summary classes.  */
     25 
     26 template <class T>
     27 class function_summary_base
     28 {
     29 public:
     30   /* Default construction takes SYMTAB as an argument.  */
     31   function_summary_base (symbol_table *symtab CXX_MEM_STAT_INFO):
     32   m_symtab (symtab),
     33   m_insertion_enabled (true),
     34   m_allocator ("function summary" PASS_MEM_STAT)
     35   {}
     36 
     37   /* Basic implementation of insert operation.  */
     38   virtual void insert (cgraph_node *, T *) {}
     39 
     40   /* Basic implementation of removal operation.  */
     41   virtual void remove (cgraph_node *, T *) {}
     42 
     43   /* Basic implementation of duplication operation.  */
     44   virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *) {}
     45 
     46   /* Enable insertion hook invocation.  */
     47   void enable_insertion_hook ()
     48   {
     49     m_insertion_enabled = true;
     50   }
     51 
     52   /* Enable insertion hook invocation.  */
     53   void disable_insertion_hook ()
     54   {
     55     m_insertion_enabled = false;
     56   }
     57 
     58 protected:
     59   /* Allocates new data that are stored within map.  */
     60   T* allocate_new ()
     61   {
     62     /* Call gcc_internal_because we do not want to call finalizer for
     63        a type T.  We call dtor explicitly.  */
     64     return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T ()
     65 		     : m_allocator.allocate () ;
     66   }
     67 
     68   /* Release an item that is stored within map.  */
     69   void release (T *item)
     70   {
     71     if (is_ggc ())
     72       ggc_delete (item);
     73     else
     74       m_allocator.remove (item);
     75   }
     76 
     77   /* Unregister all call-graph hooks.  */
     78   void unregister_hooks ();
     79 
     80   /* Internal summary insertion hook pointer.  */
     81   cgraph_node_hook_list *m_symtab_insertion_hook;
     82   /* Internal summary removal hook pointer.  */
     83   cgraph_node_hook_list *m_symtab_removal_hook;
     84   /* Internal summary duplication hook pointer.  */
     85   cgraph_2node_hook_list *m_symtab_duplication_hook;
     86   /* Symbol table the summary is registered to.  */
     87   symbol_table *m_symtab;
     88 
     89   /* Indicates if insertion hook is enabled.  */
     90   bool m_insertion_enabled;
     91 
     92 private:
     93   /* Return true when the summary uses GGC memory for allocation.  */
     94   virtual bool is_ggc () = 0;
     95 
     96   /* Object allocator for heap allocation.  */
     97   object_allocator<T> m_allocator;
     98 };
     99 
    100 template <typename T>
    101 void
    102 function_summary_base<T>::unregister_hooks ()
    103 {
    104   m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook);
    105   m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook);
    106   m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook);
    107 }
    108 
    109 /* We want to pass just pointer types as argument for function_summary
    110    template class.  */
    111 
    112 template <class T>
    113 class function_summary
    114 {
    115 private:
    116   function_summary();
    117 };
    118 
    119 /* Function summary is a helper class that is used to associate a data structure
    120    related to a callgraph node.  Typical usage can be seen in IPA passes which
    121    create a temporary pass-related structures.  The summary class registers
    122    hooks that are triggered when a new node is inserted, duplicated and deleted.
    123    A user of a summary class can ovewrite virtual methods than are triggered by
    124    the summary if such hook is triggered.  Apart from a callgraph node, the user
    125    is given a data structure tied to the node.
    126 
    127    The function summary class can work both with a heap-allocated memory and
    128    a memory gained by garbage collected memory.  */
    129 
    130 template <class T>
    131 class GTY((user)) function_summary <T *>: public function_summary_base<T>
    132 {
    133 public:
    134   /* Default construction takes SYMTAB as an argument.  */
    135   function_summary (symbol_table *symtab, bool ggc = false CXX_MEM_STAT_INFO);
    136 
    137   /* Destructor.  */
    138   virtual ~function_summary ();
    139 
    140   /* Traverses all summarys with a function F called with
    141      ARG as argument.  */
    142   template<typename Arg, bool (*f)(const T &, Arg)>
    143   void traverse (Arg a) const
    144   {
    145     m_map.template traverse <f> (a);
    146   }
    147 
    148   /* Getter for summary callgraph node pointer.  If a summary for a node
    149      does not exist it will be created.  */
    150   T* get_create (cgraph_node *node)
    151   {
    152     bool existed;
    153     T **v = &m_map.get_or_insert (node->get_uid (), &existed);
    154     if (!existed)
    155       *v = this->allocate_new ();
    156 
    157     return *v;
    158   }
    159 
    160   /* Getter for summary callgraph node pointer.  */
    161   T* get (cgraph_node *node) ATTRIBUTE_PURE
    162   {
    163     T **v = m_map.get (node->get_uid ());
    164     return v == NULL ? NULL : *v;
    165   }
    166 
    167   /* Remove node from summary.  */
    168   using function_summary_base<T>::remove;
    169   void remove (cgraph_node *node)
    170   {
    171     int uid = node->get_uid ();
    172     T **v = m_map.get (uid);
    173     if (v)
    174       {
    175 	m_map.remove (uid);
    176 	this->release (*v);
    177       }
    178   }
    179 
    180   /* Return true if a summary for the given NODE already exists.  */
    181   bool exists (cgraph_node *node)
    182   {
    183     return m_map.get (node->get_uid ()) != NULL;
    184   }
    185 
    186   /* Symbol insertion hook that is registered to symbol table.  */
    187   static void symtab_insertion (cgraph_node *node, void *data);
    188 
    189   /* Symbol removal hook that is registered to symbol table.  */
    190   static void symtab_removal (cgraph_node *node, void *data);
    191 
    192   /* Symbol duplication hook that is registered to symbol table.  */
    193   static void symtab_duplication (cgraph_node *node, cgraph_node *node2,
    194 				  void *data);
    195 
    196 protected:
    197   /* Indication if we use ggc summary.  */
    198   bool m_ggc;
    199 
    200 private:
    201   /* Indication if we use ggc summary.  */
    202   virtual bool is_ggc ()
    203   {
    204     return m_ggc;
    205   }
    206 
    207   typedef int_hash <int, 0, -1> map_hash;
    208 
    209   /* Main summary store, where summary ID is used as key.  */
    210   hash_map <map_hash, T *> m_map;
    211 
    212   template <typename U> friend void gt_ggc_mx (function_summary <U *> * const &);
    213   template <typename U> friend void gt_pch_nx (function_summary <U *> * const &);
    214   template <typename U> friend void gt_pch_nx (function_summary <U *> * const &,
    215       gt_pointer_operator, void *);
    216 };
    217 
    218 template <typename T>
    219 function_summary<T *>::function_summary (symbol_table *symtab, bool ggc
    220 					 MEM_STAT_DECL):
    221   function_summary_base<T> (symtab PASS_MEM_STAT), m_ggc (ggc),
    222   m_map (13, ggc, true, GATHER_STATISTICS PASS_MEM_STAT)
    223 {
    224   this->m_symtab_insertion_hook
    225     = this->m_symtab->add_cgraph_insertion_hook (function_summary::symtab_insertion,
    226 						 this);
    227   this->m_symtab_removal_hook
    228     = this->m_symtab->add_cgraph_removal_hook (function_summary::symtab_removal,
    229 					       this);
    230   this->m_symtab_duplication_hook
    231     = this->m_symtab->add_cgraph_duplication_hook (function_summary::symtab_duplication,
    232 						   this);
    233 }
    234 
    235 template <typename T>
    236 function_summary<T *>::~function_summary ()
    237 {
    238   this->unregister_hooks ();
    239 
    240   /* Release all summaries.  */
    241   typedef typename hash_map <map_hash, T *>::iterator map_iterator;
    242   for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
    243     this->release ((*it).second);
    244 }
    245 
    246 template <typename T>
    247 void
    248 function_summary<T *>::symtab_insertion (cgraph_node *node, void *data)
    249 {
    250   gcc_checking_assert (node->get_uid ());
    251   function_summary *summary = (function_summary <T *> *) (data);
    252 
    253   if (summary->m_insertion_enabled)
    254     summary->insert (node, summary->get_create (node));
    255 }
    256 
    257 template <typename T>
    258 void
    259 function_summary<T *>::symtab_removal (cgraph_node *node, void *data)
    260 {
    261   gcc_checking_assert (node->get_uid ());
    262   function_summary *summary = (function_summary <T *> *) (data);
    263   summary->remove (node);
    264 }
    265 
    266 template <typename T>
    267 void
    268 function_summary<T *>::symtab_duplication (cgraph_node *node,
    269 					   cgraph_node *node2, void *data)
    270 {
    271   function_summary *summary = (function_summary <T *> *) (data);
    272   T *v = summary->get (node);
    273 
    274   if (v)
    275     summary->duplicate (node, node2, v, summary->get_create (node2));
    276 }
    277 
    278 template <typename T>
    279 void
    280 gt_ggc_mx(function_summary<T *>* const &summary)
    281 {
    282   gcc_checking_assert (summary->m_ggc);
    283   gt_ggc_mx (&summary->m_map);
    284 }
    285 
    286 template <typename T>
    287 void
    288 gt_pch_nx (function_summary<T *> *const &)
    289 {
    290   gcc_unreachable ();
    291 }
    292 
    293 template <typename T>
    294 void
    295 gt_pch_nx (function_summary<T *> *const &, gt_pointer_operator, void *)
    296 {
    297   gcc_unreachable ();
    298 }
    299 
    300 /* Help template from std c++11.  */
    301 
    302 template<typename T, typename U>
    303 struct is_same
    304 {
    305     static const bool value = false;
    306 };
    307 
    308 template<typename T>
    309 struct is_same<T,T>  //specialization
    310 {
    311    static const bool value = true;
    312 };
    313 
    314 /* We want to pass just pointer types as argument for fast_function_summary
    315    template class.  */
    316 
    317 template <class T, class V>
    318 class fast_function_summary
    319 {
    320 private:
    321   fast_function_summary ();
    322 };
    323 
    324 /* Function vector summary is a fast implementation of function_summary that
    325    utilizes vector as primary storage of summaries.  */
    326 
    327 template <class T, class V>
    328 class GTY((user)) fast_function_summary <T *, V>
    329   : public function_summary_base<T>
    330 {
    331 public:
    332   /* Default construction takes SYMTAB as an argument.  */
    333   fast_function_summary (symbol_table *symtab CXX_MEM_STAT_INFO);
    334 
    335   /* Destructor.  */
    336   virtual ~fast_function_summary ();
    337 
    338   /* Traverses all summarys with a function F called with
    339      ARG as argument.  */
    340   template<typename Arg, bool (*f)(const T &, Arg)>
    341   void traverse (Arg a) const
    342   {
    343     for (unsigned i = 0; i < m_vector->length (); i++)
    344       if ((*m_vector[i]) != NULL)
    345 	f ((*m_vector)[i], a);
    346   }
    347 
    348   /* Getter for summary callgraph node pointer.  If a summary for a node
    349      does not exist it will be created.  */
    350   T* get_create (cgraph_node *node)
    351   {
    352     int id = node->get_summary_id ();
    353     if (id == -1)
    354       id = this->m_symtab->assign_summary_id (node);
    355 
    356     if ((unsigned int)id >= m_vector->length ())
    357       {
    358 	int newlen = this->m_symtab->cgraph_max_summary_id;
    359 	vec_safe_reserve (m_vector, newlen - m_vector->length ());
    360 	m_vector->quick_grow_cleared (newlen);
    361       }
    362 
    363     if ((*m_vector)[id] == NULL)
    364       (*m_vector)[id] = this->allocate_new ();
    365 
    366     return (*m_vector)[id];
    367   }
    368 
    369   /* Getter for summary callgraph node pointer.  */
    370   T* get (cgraph_node *node) ATTRIBUTE_PURE
    371   {
    372     return exists (node) ? (*m_vector)[node->get_summary_id ()] : NULL;
    373   }
    374 
    375   using function_summary_base<T>::remove;
    376   void remove (cgraph_node *node)
    377   {
    378     if (exists (node))
    379       {
    380 	int id = node->get_summary_id ();
    381 	this->release ((*m_vector)[id]);
    382 	(*m_vector)[id] = NULL;
    383       }
    384   }
    385 
    386   /* Return true if a summary for the given NODE already exists.  */
    387   bool exists (cgraph_node *node)
    388   {
    389     int id = node->get_summary_id ();
    390     return (id != -1
    391 	    && (unsigned int)id < m_vector->length ()
    392 	    && (*m_vector)[id] != NULL);
    393   }
    394 
    395   /* Symbol insertion hook that is registered to symbol table.  */
    396   static void symtab_insertion (cgraph_node *node, void *data);
    397 
    398   /* Symbol removal hook that is registered to symbol table.  */
    399   static void symtab_removal (cgraph_node *node, void *data);
    400 
    401   /* Symbol duplication hook that is registered to symbol table.  */
    402   static void symtab_duplication (cgraph_node *node, cgraph_node *node2,
    403 				  void *data);
    404 
    405 private:
    406   virtual bool is_ggc ();
    407 
    408   /* Summary is stored in the vector.  */
    409   vec <T *, V> *m_vector;
    410 
    411   template <typename U> friend void gt_ggc_mx (fast_function_summary <U *, va_gc> * const &);
    412   template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &);
    413   template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &,
    414       gt_pointer_operator, void *);
    415 };
    416 
    417 template <typename T, typename V>
    418 fast_function_summary<T *, V>::fast_function_summary (symbol_table *symtab MEM_STAT_DECL):
    419   function_summary_base<T> (symtab PASS_MEM_STAT), m_vector (NULL)
    420 {
    421   vec_alloc (m_vector, 13 PASS_MEM_STAT);
    422   this->m_symtab_insertion_hook
    423     = this->m_symtab->add_cgraph_insertion_hook (fast_function_summary::symtab_insertion,
    424 						 this);
    425   this->m_symtab_removal_hook
    426     = this->m_symtab->add_cgraph_removal_hook (fast_function_summary::symtab_removal,
    427 					       this);
    428   this->m_symtab_duplication_hook
    429     = this->m_symtab->add_cgraph_duplication_hook (fast_function_summary::symtab_duplication,
    430 						   this);
    431 }
    432 
    433 template <typename T, typename V>
    434 fast_function_summary<T *, V>::~fast_function_summary ()
    435 {
    436   this->unregister_hooks ();
    437 
    438   /* Release all summaries.  */
    439   for (unsigned i = 0; i < m_vector->length (); i++)
    440     if ((*m_vector)[i] != NULL)
    441       this->release ((*m_vector)[i]);
    442   vec_free (m_vector);
    443 }
    444 
    445 template <typename T, typename V>
    446 void
    447 fast_function_summary<T *, V>::symtab_insertion (cgraph_node *node, void *data)
    448 {
    449   gcc_checking_assert (node->get_uid ());
    450   fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
    451 
    452   if (summary->m_insertion_enabled)
    453     summary->insert (node, summary->get_create (node));
    454 }
    455 
    456 template <typename T, typename V>
    457 void
    458 fast_function_summary<T *, V>::symtab_removal (cgraph_node *node, void *data)
    459 {
    460   gcc_checking_assert (node->get_uid ());
    461   fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
    462 
    463   if (summary->exists (node))
    464     summary->remove (node);
    465 }
    466 
    467 template <typename T, typename V>
    468 void
    469 fast_function_summary<T *, V>::symtab_duplication (cgraph_node *node,
    470 						   cgraph_node *node2,
    471 						   void *data)
    472 {
    473   fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
    474   T *v = summary->get (node);
    475 
    476   if (v)
    477     {
    478       T *duplicate = summary->get_create (node2);
    479       summary->duplicate (node, node2, v, duplicate);
    480     }
    481 }
    482 
    483 template <typename T, typename V>
    484 inline bool
    485 fast_function_summary<T *, V>::is_ggc ()
    486 {
    487   return is_same<V, va_gc>::value;
    488 }
    489 
    490 template <typename T>
    491 void
    492 gt_ggc_mx (fast_function_summary<T *, va_heap>* const &)
    493 {
    494 }
    495 
    496 template <typename T>
    497 void
    498 gt_pch_nx (fast_function_summary<T *, va_heap>* const &)
    499 {
    500 }
    501 
    502 template <typename T>
    503 void
    504 gt_pch_nx (fast_function_summary<T *, va_heap>* const&, gt_pointer_operator,
    505 	   void *)
    506 {
    507 }
    508 
    509 template <typename T>
    510 void
    511 gt_ggc_mx (fast_function_summary<T *, va_gc>* const &summary)
    512 {
    513   ggc_test_and_set_mark (summary->m_vector);
    514   gt_ggc_mx (summary->m_vector);
    515 }
    516 
    517 template <typename T>
    518 void
    519 gt_pch_nx (fast_function_summary<T *, va_gc> *const &)
    520 {
    521   gcc_unreachable ();
    522 }
    523 
    524 template <typename T>
    525 void
    526 gt_pch_nx (fast_function_summary<T *, va_gc> *const &, gt_pointer_operator,
    527 	   void *)
    528 {
    529   gcc_unreachable ();
    530 }
    531 
    532 /* Base class for call_summary and fast_call_summary classes.  */
    533 
    534 template <class T>
    535 class call_summary_base
    536 {
    537 public:
    538   /* Default construction takes SYMTAB as an argument.  */
    539   call_summary_base (symbol_table *symtab CXX_MEM_STAT_INFO):
    540   m_symtab (symtab),
    541   m_initialize_when_cloning (false),
    542   m_allocator ("call summary" PASS_MEM_STAT)
    543   {}
    544 
    545   /* Basic implementation of removal operation.  */
    546   virtual void remove (cgraph_edge *, T *) {}
    547 
    548   /* Basic implementation of duplication operation.  */
    549   virtual void duplicate (cgraph_edge *, cgraph_edge *, T *, T *) {}
    550 
    551 protected:
    552   /* Allocates new data that are stored within map.  */
    553   T* allocate_new ()
    554   {
    555     /* Call gcc_internal_because we do not want to call finalizer for
    556        a type T.  We call dtor explicitly.  */
    557     return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T ()
    558 		     : m_allocator.allocate ();
    559   }
    560 
    561   /* Release an item that is stored within map.  */
    562   void release (T *item)
    563   {
    564     if (is_ggc ())
    565       ggc_delete (item);
    566     else
    567       m_allocator.remove (item);
    568   }
    569 
    570   /* Unregister all call-graph hooks.  */
    571   void unregister_hooks ();
    572 
    573   /* Symbol table the summary is registered to.  */
    574   symbol_table *m_symtab;
    575 
    576   /* Internal summary removal hook pointer.  */
    577   cgraph_edge_hook_list *m_symtab_removal_hook;
    578   /* Internal summary duplication hook pointer.  */
    579   cgraph_2edge_hook_list *m_symtab_duplication_hook;
    580   /* Initialize summary for an edge that is cloned.  */
    581   bool m_initialize_when_cloning;
    582 
    583 private:
    584   /* Return true when the summary uses GGC memory for allocation.  */
    585   virtual bool is_ggc () = 0;
    586 
    587   /* Object allocator for heap allocation.  */
    588   object_allocator<T> m_allocator;
    589 };
    590 
    591 template <typename T>
    592 void
    593 call_summary_base<T>::unregister_hooks ()
    594 {
    595   m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
    596   m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
    597 }
    598 
    599 /* An impossible class templated by non-pointers so, which makes sure that only
    600    summaries gathering pointers can be created.  */
    601 
    602 template <class T>
    603 class call_summary
    604 {
    605 private:
    606   call_summary ();
    607 };
    608 
    609 /* Class to store auxiliary information about call graph edges.  */
    610 
    611 template <class T>
    612 class GTY((user)) call_summary <T *>: public call_summary_base<T>
    613 {
    614 public:
    615   /* Default construction takes SYMTAB as an argument.  */
    616   call_summary (symbol_table *symtab, bool ggc = false
    617 		CXX_MEM_STAT_INFO)
    618   : call_summary_base<T> (symtab PASS_MEM_STAT), m_ggc (ggc),
    619     m_map (13, ggc, true, GATHER_STATISTICS PASS_MEM_STAT)
    620   {
    621     this->m_symtab_removal_hook
    622       = this->m_symtab->add_edge_removal_hook (call_summary::symtab_removal,
    623 					       this);
    624     this->m_symtab_duplication_hook
    625       = this->m_symtab->add_edge_duplication_hook (call_summary::symtab_duplication,
    626 						   this);
    627   }
    628 
    629   /* Destructor.  */
    630   virtual ~call_summary ();
    631 
    632   /* Traverses all summarys with an edge E called with
    633      ARG as argument.  */
    634   template<typename Arg, bool (*f)(const T &, Arg)>
    635   void traverse (Arg a) const
    636   {
    637     m_map.template traverse <f> (a);
    638   }
    639 
    640   /* Getter for summary callgraph edge pointer.
    641      If a summary for an edge does not exist, it will be created.  */
    642   T* get_create (cgraph_edge *edge)
    643   {
    644     bool existed;
    645     T **v = &m_map.get_or_insert (edge->get_uid (), &existed);
    646     if (!existed)
    647       *v = this->allocate_new ();
    648 
    649     return *v;
    650   }
    651 
    652   /* Getter for summary callgraph edge pointer.  */
    653   T* get (cgraph_edge *edge) ATTRIBUTE_PURE
    654   {
    655     T **v = m_map.get (edge->get_uid ());
    656     return v == NULL ? NULL : *v;
    657   }
    658 
    659   /* Remove edge from summary.  */
    660   using call_summary_base<T>::remove;
    661   void remove (cgraph_edge *edge)
    662   {
    663     int uid = edge->get_uid ();
    664     T **v = m_map.get (uid);
    665     if (v)
    666       {
    667 	m_map.remove (uid);
    668 	this->release (*v);
    669       }
    670   }
    671 
    672   /* Return true if a summary for the given EDGE already exists.  */
    673   bool exists (cgraph_edge *edge)
    674   {
    675     return m_map.get (edge->get_uid ()) != NULL;
    676   }
    677 
    678   /* Symbol removal hook that is registered to symbol table.  */
    679   static void symtab_removal (cgraph_edge *edge, void *data);
    680 
    681   /* Symbol duplication hook that is registered to symbol table.  */
    682   static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2,
    683 				  void *data);
    684 
    685 protected:
    686   /* Indication if we use ggc summary.  */
    687   bool m_ggc;
    688 
    689 private:
    690   /* Indication if we use ggc summary.  */
    691   virtual bool is_ggc ()
    692   {
    693     return m_ggc;
    694   }
    695 
    696   typedef int_hash <int, 0, -1> map_hash;
    697 
    698   /* Main summary store, where summary ID is used as key.  */
    699   hash_map <map_hash, T *> m_map;
    700 
    701   template <typename U> friend void gt_ggc_mx (call_summary <U *> * const &);
    702   template <typename U> friend void gt_pch_nx (call_summary <U *> * const &);
    703   template <typename U> friend void gt_pch_nx (call_summary <U *> * const &,
    704       gt_pointer_operator, void *);
    705 };
    706 
    707 template <typename T>
    708 call_summary<T *>::~call_summary ()
    709 {
    710   this->unregister_hooks ();
    711 
    712   /* Release all summaries.  */
    713   typedef typename hash_map <map_hash, T *>::iterator map_iterator;
    714   for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
    715     this->release ((*it).second);
    716 }
    717 
    718 template <typename T>
    719 void
    720 call_summary<T *>::symtab_removal (cgraph_edge *edge, void *data)
    721 {
    722   call_summary *summary = (call_summary <T *> *) (data);
    723   summary->remove (edge);
    724 }
    725 
    726 template <typename T>
    727 void
    728 call_summary<T *>::symtab_duplication (cgraph_edge *edge1,
    729 				       cgraph_edge *edge2, void *data)
    730 {
    731   call_summary *summary = (call_summary <T *> *) (data);
    732   T *edge1_summary = NULL;
    733 
    734   if (summary->m_initialize_when_cloning)
    735     edge1_summary = summary->get_create (edge1);
    736   else
    737     edge1_summary = summary->get (edge1);
    738 
    739   if (edge1_summary)
    740     summary->duplicate (edge1, edge2, edge1_summary,
    741 			summary->get_create (edge2));
    742 }
    743 
    744 template <typename T>
    745 void
    746 gt_ggc_mx(call_summary<T *>* const &summary)
    747 {
    748   gcc_checking_assert (summary->m_ggc);
    749   gt_ggc_mx (&summary->m_map);
    750 }
    751 
    752 template <typename T>
    753 void
    754 gt_pch_nx (call_summary<T *> *const &)
    755 {
    756   gcc_unreachable ();
    757 }
    758 
    759 template <typename T>
    760 void
    761 gt_pch_nx (call_summary<T *> *const &, gt_pointer_operator, void *)
    762 {
    763   gcc_unreachable ();
    764 }
    765 
    766 /* We want to pass just pointer types as argument for fast_call_summary
    767    template class.  */
    768 
    769 template <class T, class V>
    770 class fast_call_summary
    771 {
    772 private:
    773   fast_call_summary ();
    774 };
    775 
    776 /* Call vector summary is a fast implementation of call_summary that
    777    utilizes vector as primary storage of summaries.  */
    778 
    779 template <class T, class V>
    780 class GTY((user)) fast_call_summary <T *, V>: public call_summary_base<T>
    781 {
    782 public:
    783   /* Default construction takes SYMTAB as an argument.  */
    784   fast_call_summary (symbol_table *symtab CXX_MEM_STAT_INFO)
    785   : call_summary_base<T> (symtab PASS_MEM_STAT), m_vector (NULL)
    786   {
    787     vec_alloc (m_vector, 13 PASS_MEM_STAT);
    788     this->m_symtab_removal_hook
    789       = this->m_symtab->add_edge_removal_hook (fast_call_summary::symtab_removal,
    790 					       this);
    791     this->m_symtab_duplication_hook
    792       = this->m_symtab->add_edge_duplication_hook (fast_call_summary::symtab_duplication,
    793 						   this);
    794   }
    795 
    796   /* Destructor.  */
    797   virtual ~fast_call_summary ();
    798 
    799   /* Traverses all summarys with an edge F called with
    800      ARG as argument.  */
    801   template<typename Arg, bool (*f)(const T &, Arg)>
    802   void traverse (Arg a) const
    803   {
    804     for (unsigned i = 0; i < m_vector->length (); i++)
    805       if ((*m_vector[i]) != NULL)
    806 	f ((*m_vector)[i], a);
    807   }
    808 
    809   /* Getter for summary callgraph edge pointer.
    810      If a summary for an edge does not exist, it will be created.  */
    811   T* get_create (cgraph_edge *edge)
    812   {
    813     int id = edge->get_summary_id ();
    814     if (id == -1)
    815       id = this->m_symtab->assign_summary_id (edge);
    816 
    817     if ((unsigned)id >= m_vector->length ())
    818       {
    819 	int newlen = this->m_symtab->edges_max_summary_id;
    820 	m_vector->reserve (newlen - m_vector->length ());
    821 	m_vector->quick_grow_cleared (newlen);
    822       }
    823 
    824     if ((*m_vector)[id] == NULL)
    825       (*m_vector)[id] = this->allocate_new ();
    826 
    827     return (*m_vector)[id];
    828   }
    829 
    830   /* Getter for summary callgraph edge pointer.  */
    831   T* get (cgraph_edge *edge) ATTRIBUTE_PURE
    832   {
    833     return exists (edge) ? (*m_vector)[edge->get_summary_id ()] : NULL;
    834   }
    835 
    836   /* Remove edge from summary.  */
    837   using call_summary_base<T>::remove;
    838   void remove (cgraph_edge *edge)
    839   {
    840     if (exists (edge))
    841       {
    842 	int id = edge->get_summary_id ();
    843 	this->release ((*m_vector)[id]);
    844 	(*m_vector)[id] = NULL;
    845       }
    846   }
    847 
    848   /* Return true if a summary for the given EDGE already exists.  */
    849   bool exists (cgraph_edge *edge)
    850   {
    851     int id = edge->get_summary_id ();
    852     return (id != -1
    853 	    && (unsigned)id < m_vector->length ()
    854 	    && (*m_vector)[id] != NULL);
    855   }
    856 
    857   /* Symbol removal hook that is registered to symbol table.  */
    858   static void symtab_removal (cgraph_edge *edge, void *data);
    859 
    860   /* Symbol duplication hook that is registered to symbol table.  */
    861   static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2,
    862 				  void *data);
    863 
    864 private:
    865   virtual bool is_ggc ();
    866 
    867   /* Summary is stored in the vector.  */
    868   vec <T *, V> *m_vector;
    869 
    870   template <typename U> friend void gt_ggc_mx (fast_call_summary <U *, va_gc> * const &);
    871   template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &);
    872   template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &,
    873       gt_pointer_operator, void *);
    874 };
    875 
    876 template <typename T, typename V>
    877 fast_call_summary<T *, V>::~fast_call_summary ()
    878 {
    879   this->unregister_hooks ();
    880 
    881   /* Release all summaries.  */
    882   for (unsigned i = 0; i < m_vector->length (); i++)
    883     if ((*m_vector)[i] != NULL)
    884       this->release ((*m_vector)[i]);
    885   vec_free (m_vector);
    886 }
    887 
    888 template <typename T, typename V>
    889 void
    890 fast_call_summary<T *, V>::symtab_removal (cgraph_edge *edge, void *data)
    891 {
    892   fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
    893   summary->remove (edge);
    894 }
    895 
    896 template <typename T, typename V>
    897 void
    898 fast_call_summary<T *, V>::symtab_duplication (cgraph_edge *edge1,
    899 						 cgraph_edge *edge2, void *data)
    900 {
    901   fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
    902   T *edge1_summary = NULL;
    903 
    904   if (summary->m_initialize_when_cloning)
    905     edge1_summary = summary->get_create (edge1);
    906   else
    907     edge1_summary = summary->get (edge1);
    908 
    909   if (edge1_summary)
    910     {
    911       T *duplicate = summary->get_create (edge2);
    912       summary->duplicate (edge1, edge2, edge1_summary, duplicate);
    913     }
    914 }
    915 
    916 template <typename T, typename V>
    917 inline bool
    918 fast_call_summary<T *, V>::is_ggc ()
    919 {
    920   return is_same<V, va_gc>::value;
    921 }
    922 
    923 template <typename T>
    924 void
    925 gt_ggc_mx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED)
    926 {
    927 }
    928 
    929 template <typename T>
    930 void
    931 gt_pch_nx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED)
    932 {
    933 }
    934 
    935 template <typename T>
    936 void
    937 gt_pch_nx (fast_call_summary<T *, va_heap>* const& summary ATTRIBUTE_UNUSED,
    938 	   gt_pointer_operator op ATTRIBUTE_UNUSED,
    939 	   void *cookie ATTRIBUTE_UNUSED)
    940 {
    941 }
    942 
    943 template <typename T>
    944 void
    945 gt_ggc_mx (fast_call_summary<T *, va_gc>* const &summary)
    946 {
    947   ggc_test_and_set_mark (summary->m_vector);
    948   gt_ggc_mx (&summary->m_vector);
    949 }
    950 
    951 template <typename T>
    952 void
    953 gt_pch_nx (fast_call_summary<T *, va_gc> *const &)
    954 {
    955   gcc_unreachable ();
    956 }
    957 
    958 template <typename T>
    959 void
    960 gt_pch_nx (fast_call_summary<T *, va_gc> *const &, gt_pointer_operator, void *)
    961 {
    962   gcc_unreachable ();
    963 }
    964 
    965 #endif  /* GCC_SYMBOL_SUMMARY_H  */
    966