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