xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/symbol-summary.h (revision 23f5f46327e37e7811da3520f4bb933f9489322f)
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.  */
function_summary_base(symbol_table * symtab CXX_MEM_STAT_INFO)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.  */
insert(cgraph_node *,T *)38   virtual void insert (cgraph_node *, T *) {}
39 
40   /* Basic implementation of removal operation.  */
remove(cgraph_node *,T *)41   virtual void remove (cgraph_node *, T *) {}
42 
43   /* Basic implementation of duplication operation.  */
duplicate(cgraph_node *,cgraph_node *,T *,T *)44   virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *) {}
45 
46   /* Enable insertion hook invocation.  */
enable_insertion_hook()47   void enable_insertion_hook ()
48   {
49     m_insertion_enabled = true;
50   }
51 
52   /* Enable insertion hook invocation.  */
disable_insertion_hook()53   void disable_insertion_hook ()
54   {
55     m_insertion_enabled = false;
56   }
57 
58 protected:
59   /* Allocates new data that are stored within map.  */
allocate_new()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.  */
release(T * item)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
unregister_hooks()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>
class(user)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>
function_summary(symbol_table * symtab,bool ggc MEM_STAT_DECL)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>
~function_summary()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
symtab_insertion(cgraph_node * node,void * data)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
symtab_removal(cgraph_node * node,void * data)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
symtab_duplication(cgraph_node * node,cgraph_node * node2,void * data)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
gt_ggc_mx(function_summary<T * > * const & summary)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
gt_pch_nx(function_summary<T * > * const &)288 gt_pch_nx (function_summary<T *> *const &)
289 {
290   gcc_unreachable ();
291 }
292 
293 template <typename T>
294 void
gt_pch_nx(function_summary<T * > * const &,gt_pointer_operator,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