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.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       vec_safe_grow_cleared (m_vector,
358 			     this->m_symtab->cgraph_max_summary_id);
359 
360     if ((*m_vector)[id] == NULL)
361       (*m_vector)[id] = this->allocate_new ();
362 
363     return (*m_vector)[id];
364   }
365 
366   /* Getter for summary callgraph node pointer.  */
367   T* get (cgraph_node *node) ATTRIBUTE_PURE
368   {
369     return exists (node) ? (*m_vector)[node->get_summary_id ()] : NULL;
370   }
371 
372   using function_summary_base<T>::remove;
373   void remove (cgraph_node *node)
374   {
375     if (exists (node))
376       {
377 	int id = node->get_summary_id ();
378 	this->release ((*m_vector)[id]);
379 	(*m_vector)[id] = NULL;
380       }
381   }
382 
383   /* Return true if a summary for the given NODE already exists.  */
384   bool exists (cgraph_node *node)
385   {
386     int id = node->get_summary_id ();
387     return (id != -1
388 	    && (unsigned int)id < m_vector->length ()
389 	    && (*m_vector)[id] != NULL);
390   }
391 
392   /* Symbol insertion hook that is registered to symbol table.  */
393   static void symtab_insertion (cgraph_node *node, void *data);
394 
395   /* Symbol removal hook that is registered to symbol table.  */
396   static void symtab_removal (cgraph_node *node, void *data);
397 
398   /* Symbol duplication hook that is registered to symbol table.  */
399   static void symtab_duplication (cgraph_node *node, cgraph_node *node2,
400 				  void *data);
401 
402 private:
403   virtual bool is_ggc ();
404 
405   /* Summary is stored in the vector.  */
406   vec <T *, V> *m_vector;
407 
408   template <typename U> friend void gt_ggc_mx (fast_function_summary <U *, va_gc> * const &);
409   template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &);
410   template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &,
411       gt_pointer_operator, void *);
412 };
413 
414 template <typename T, typename V>
415 fast_function_summary<T *, V>::fast_function_summary (symbol_table *symtab MEM_STAT_DECL):
416   function_summary_base<T> (symtab PASS_MEM_STAT), m_vector (NULL)
417 {
418   vec_alloc (m_vector, 13 PASS_MEM_STAT);
419   this->m_symtab_insertion_hook
420     = this->m_symtab->add_cgraph_insertion_hook (fast_function_summary::symtab_insertion,
421 						 this);
422   this->m_symtab_removal_hook
423     = this->m_symtab->add_cgraph_removal_hook (fast_function_summary::symtab_removal,
424 					       this);
425   this->m_symtab_duplication_hook
426     = this->m_symtab->add_cgraph_duplication_hook (fast_function_summary::symtab_duplication,
427 						   this);
428 }
429 
430 template <typename T, typename V>
431 fast_function_summary<T *, V>::~fast_function_summary ()
432 {
433   this->unregister_hooks ();
434 
435   /* Release all summaries.  */
436   for (unsigned i = 0; i < m_vector->length (); i++)
437     if ((*m_vector)[i] != NULL)
438       this->release ((*m_vector)[i]);
439   vec_free (m_vector);
440 }
441 
442 template <typename T, typename V>
443 void
444 fast_function_summary<T *, V>::symtab_insertion (cgraph_node *node, void *data)
445 {
446   gcc_checking_assert (node->get_uid ());
447   fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
448 
449   if (summary->m_insertion_enabled)
450     summary->insert (node, summary->get_create (node));
451 }
452 
453 template <typename T, typename V>
454 void
455 fast_function_summary<T *, V>::symtab_removal (cgraph_node *node, void *data)
456 {
457   gcc_checking_assert (node->get_uid ());
458   fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
459 
460   if (summary->exists (node))
461     summary->remove (node);
462 }
463 
464 template <typename T, typename V>
465 void
466 fast_function_summary<T *, V>::symtab_duplication (cgraph_node *node,
467 						   cgraph_node *node2,
468 						   void *data)
469 {
470   fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
471   T *v = summary->get (node);
472 
473   if (v)
474     {
475       T *duplicate = summary->get_create (node2);
476       summary->duplicate (node, node2, v, duplicate);
477     }
478 }
479 
480 template <typename T, typename V>
481 inline bool
482 fast_function_summary<T *, V>::is_ggc ()
483 {
484   return is_same<V, va_gc>::value;
485 }
486 
487 template <typename T>
488 void
489 gt_ggc_mx (fast_function_summary<T *, va_heap>* const &)
490 {
491 }
492 
493 template <typename T>
494 void
495 gt_pch_nx (fast_function_summary<T *, va_heap>* const &)
496 {
497 }
498 
499 template <typename T>
500 void
501 gt_pch_nx (fast_function_summary<T *, va_heap>* const&, gt_pointer_operator,
502 	   void *)
503 {
504 }
505 
506 template <typename T>
507 void
508 gt_ggc_mx (fast_function_summary<T *, va_gc>* const &summary)
509 {
510   ggc_test_and_set_mark (summary->m_vector);
511   gt_ggc_mx (summary->m_vector);
512 }
513 
514 template <typename T>
515 void
516 gt_pch_nx (fast_function_summary<T *, va_gc> *const &)
517 {
518   gcc_unreachable ();
519 }
520 
521 template <typename T>
522 void
523 gt_pch_nx (fast_function_summary<T *, va_gc> *const &, gt_pointer_operator,
524 	   void *)
525 {
526   gcc_unreachable ();
527 }
528 
529 /* Base class for call_summary and fast_call_summary classes.  */
530 
531 template <class T>
532 class call_summary_base
533 {
534 public:
535   /* Default construction takes SYMTAB as an argument.  */
536   call_summary_base (symbol_table *symtab CXX_MEM_STAT_INFO):
537   m_symtab (symtab),
538   m_initialize_when_cloning (false),
539   m_allocator ("call summary" PASS_MEM_STAT)
540   {}
541 
542   /* Basic implementation of removal operation.  */
543   virtual void remove (cgraph_edge *, T *) {}
544 
545   /* Basic implementation of duplication operation.  */
546   virtual void duplicate (cgraph_edge *, cgraph_edge *, T *, T *) {}
547 
548 protected:
549   /* Allocates new data that are stored within map.  */
550   T* allocate_new ()
551   {
552     /* Call gcc_internal_because we do not want to call finalizer for
553        a type T.  We call dtor explicitly.  */
554     return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T ()
555 		     : m_allocator.allocate ();
556   }
557 
558   /* Release an item that is stored within map.  */
559   void release (T *item)
560   {
561     if (is_ggc ())
562       ggc_delete (item);
563     else
564       m_allocator.remove (item);
565   }
566 
567   /* Unregister all call-graph hooks.  */
568   void unregister_hooks ();
569 
570   /* Symbol table the summary is registered to.  */
571   symbol_table *m_symtab;
572 
573   /* Internal summary removal hook pointer.  */
574   cgraph_edge_hook_list *m_symtab_removal_hook;
575   /* Internal summary duplication hook pointer.  */
576   cgraph_2edge_hook_list *m_symtab_duplication_hook;
577   /* Initialize summary for an edge that is cloned.  */
578   bool m_initialize_when_cloning;
579 
580 private:
581   /* Return true when the summary uses GGC memory for allocation.  */
582   virtual bool is_ggc () = 0;
583 
584   /* Object allocator for heap allocation.  */
585   object_allocator<T> m_allocator;
586 };
587 
588 template <typename T>
589 void
590 call_summary_base<T>::unregister_hooks ()
591 {
592   m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
593   m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
594 }
595 
596 /* An impossible class templated by non-pointers so, which makes sure that only
597    summaries gathering pointers can be created.  */
598 
599 template <class T>
600 class call_summary
601 {
602 private:
603   call_summary ();
604 };
605 
606 /* Class to store auxiliary information about call graph edges.  */
607 
608 template <class T>
609 class GTY((user)) call_summary <T *>: public call_summary_base<T>
610 {
611 public:
612   /* Default construction takes SYMTAB as an argument.  */
613   call_summary (symbol_table *symtab, bool ggc = false
614 		CXX_MEM_STAT_INFO)
615   : call_summary_base<T> (symtab PASS_MEM_STAT), m_ggc (ggc),
616     m_map (13, ggc, true, GATHER_STATISTICS PASS_MEM_STAT)
617   {
618     this->m_symtab_removal_hook
619       = this->m_symtab->add_edge_removal_hook (call_summary::symtab_removal,
620 					       this);
621     this->m_symtab_duplication_hook
622       = this->m_symtab->add_edge_duplication_hook (call_summary::symtab_duplication,
623 						   this);
624   }
625 
626   /* Destructor.  */
627   virtual ~call_summary ();
628 
629   /* Traverses all summarys with an edge E called with
630      ARG as argument.  */
631   template<typename Arg, bool (*f)(const T &, Arg)>
632   void traverse (Arg a) const
633   {
634     m_map.traverse <f> (a);
635   }
636 
637   /* Getter for summary callgraph edge pointer.
638      If a summary for an edge does not exist, it will be created.  */
639   T* get_create (cgraph_edge *edge)
640   {
641     bool existed;
642     T **v = &m_map.get_or_insert (edge->get_uid (), &existed);
643     if (!existed)
644       *v = this->allocate_new ();
645 
646     return *v;
647   }
648 
649   /* Getter for summary callgraph edge pointer.  */
650   T* get (cgraph_edge *edge) ATTRIBUTE_PURE
651   {
652     T **v = m_map.get (edge->get_uid ());
653     return v == NULL ? NULL : *v;
654   }
655 
656   /* Remove edge from summary.  */
657   using call_summary_base<T>::remove;
658   void remove (cgraph_edge *edge)
659   {
660     int uid = edge->get_uid ();
661     T **v = m_map.get (uid);
662     if (v)
663       {
664 	m_map.remove (uid);
665 	this->release (*v);
666       }
667   }
668 
669   /* Return true if a summary for the given EDGE already exists.  */
670   bool exists (cgraph_edge *edge)
671   {
672     return m_map.get (edge->get_uid ()) != NULL;
673   }
674 
675   /* Symbol removal hook that is registered to symbol table.  */
676   static void symtab_removal (cgraph_edge *edge, void *data);
677 
678   /* Symbol duplication hook that is registered to symbol table.  */
679   static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2,
680 				  void *data);
681 
682 protected:
683   /* Indication if we use ggc summary.  */
684   bool m_ggc;
685 
686 private:
687   /* Indication if we use ggc summary.  */
688   virtual bool is_ggc ()
689   {
690     return m_ggc;
691   }
692 
693   typedef int_hash <int, 0, -1> map_hash;
694 
695   /* Main summary store, where summary ID is used as key.  */
696   hash_map <map_hash, T *> m_map;
697 
698   template <typename U> friend void gt_ggc_mx (call_summary <U *> * const &);
699   template <typename U> friend void gt_pch_nx (call_summary <U *> * const &);
700   template <typename U> friend void gt_pch_nx (call_summary <U *> * const &,
701       gt_pointer_operator, void *);
702 };
703 
704 template <typename T>
705 call_summary<T *>::~call_summary ()
706 {
707   this->unregister_hooks ();
708 
709   /* Release all summaries.  */
710   typedef typename hash_map <map_hash, T *>::iterator map_iterator;
711   for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
712     this->release ((*it).second);
713 }
714 
715 template <typename T>
716 void
717 call_summary<T *>::symtab_removal (cgraph_edge *edge, void *data)
718 {
719   call_summary *summary = (call_summary <T *> *) (data);
720   summary->remove (edge);
721 }
722 
723 template <typename T>
724 void
725 call_summary<T *>::symtab_duplication (cgraph_edge *edge1,
726 				       cgraph_edge *edge2, void *data)
727 {
728   call_summary *summary = (call_summary <T *> *) (data);
729   T *edge1_summary = NULL;
730 
731   if (summary->m_initialize_when_cloning)
732     edge1_summary = summary->get_create (edge1);
733   else
734     edge1_summary = summary->get (edge1);
735 
736   if (edge1_summary)
737     summary->duplicate (edge1, edge2, edge1_summary,
738 			summary->get_create (edge2));
739 }
740 
741 template <typename T>
742 void
743 gt_ggc_mx(call_summary<T *>* const &summary)
744 {
745   gcc_checking_assert (summary->m_ggc);
746   gt_ggc_mx (&summary->m_map);
747 }
748 
749 template <typename T>
750 void
751 gt_pch_nx (call_summary<T *> *const &)
752 {
753   gcc_unreachable ();
754 }
755 
756 template <typename T>
757 void
758 gt_pch_nx (call_summary<T *> *const &, gt_pointer_operator, void *)
759 {
760   gcc_unreachable ();
761 }
762 
763 /* We want to pass just pointer types as argument for fast_call_summary
764    template class.  */
765 
766 template <class T, class V>
767 class fast_call_summary
768 {
769 private:
770   fast_call_summary ();
771 };
772 
773 /* Call vector summary is a fast implementation of call_summary that
774    utilizes vector as primary storage of summaries.  */
775 
776 template <class T, class V>
777 class GTY((user)) fast_call_summary <T *, V>: public call_summary_base<T>
778 {
779 public:
780   /* Default construction takes SYMTAB as an argument.  */
781   fast_call_summary (symbol_table *symtab CXX_MEM_STAT_INFO)
782   : call_summary_base<T> (symtab PASS_MEM_STAT), m_vector (NULL)
783   {
784     vec_alloc (m_vector, 13 PASS_MEM_STAT);
785     this->m_symtab_removal_hook
786       = this->m_symtab->add_edge_removal_hook (fast_call_summary::symtab_removal,
787 					       this);
788     this->m_symtab_duplication_hook
789       = this->m_symtab->add_edge_duplication_hook (fast_call_summary::symtab_duplication,
790 						   this);
791   }
792 
793   /* Destructor.  */
794   virtual ~fast_call_summary ();
795 
796   /* Traverses all summarys with an edge F called with
797      ARG as argument.  */
798   template<typename Arg, bool (*f)(const T &, Arg)>
799   void traverse (Arg a) const
800   {
801     for (unsigned i = 0; i < m_vector->length (); i++)
802       if ((*m_vector[i]) != NULL)
803 	f ((*m_vector)[i], a);
804   }
805 
806   /* Getter for summary callgraph edge pointer.
807      If a summary for an edge does not exist, it will be created.  */
808   T* get_create (cgraph_edge *edge)
809   {
810     int id = edge->get_summary_id ();
811     if (id == -1)
812       id = this->m_symtab->assign_summary_id (edge);
813 
814     if ((unsigned)id >= m_vector->length ())
815       vec_safe_grow_cleared (m_vector, this->m_symtab->edges_max_summary_id);
816 
817     if ((*m_vector)[id] == NULL)
818       (*m_vector)[id] = this->allocate_new ();
819 
820     return (*m_vector)[id];
821   }
822 
823   /* Getter for summary callgraph edge pointer.  */
824   T* get (cgraph_edge *edge) ATTRIBUTE_PURE
825   {
826     return exists (edge) ? (*m_vector)[edge->get_summary_id ()] : NULL;
827   }
828 
829   /* Remove edge from summary.  */
830   using call_summary_base<T>::remove;
831   void remove (cgraph_edge *edge)
832   {
833     if (exists (edge))
834       {
835 	int id = edge->get_summary_id ();
836 	this->release ((*m_vector)[id]);
837 	(*m_vector)[id] = NULL;
838       }
839   }
840 
841   /* Return true if a summary for the given EDGE already exists.  */
842   bool exists (cgraph_edge *edge)
843   {
844     int id = edge->get_summary_id ();
845     return (id != -1
846 	    && (unsigned)id < m_vector->length ()
847 	    && (*m_vector)[id] != NULL);
848   }
849 
850   /* Symbol removal hook that is registered to symbol table.  */
851   static void symtab_removal (cgraph_edge *edge, void *data);
852 
853   /* Symbol duplication hook that is registered to symbol table.  */
854   static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2,
855 				  void *data);
856 
857 private:
858   virtual bool is_ggc ();
859 
860   /* Summary is stored in the vector.  */
861   vec <T *, V> *m_vector;
862 
863   template <typename U> friend void gt_ggc_mx (fast_call_summary <U *, va_gc> * const &);
864   template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &);
865   template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &,
866       gt_pointer_operator, void *);
867 };
868 
869 template <typename T, typename V>
870 fast_call_summary<T *, V>::~fast_call_summary ()
871 {
872   this->unregister_hooks ();
873 
874   /* Release all summaries.  */
875   for (unsigned i = 0; i < m_vector->length (); i++)
876     if ((*m_vector)[i] != NULL)
877       this->release ((*m_vector)[i]);
878   vec_free (m_vector);
879 }
880 
881 template <typename T, typename V>
882 void
883 fast_call_summary<T *, V>::symtab_removal (cgraph_edge *edge, void *data)
884 {
885   fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
886   summary->remove (edge);
887 }
888 
889 template <typename T, typename V>
890 void
891 fast_call_summary<T *, V>::symtab_duplication (cgraph_edge *edge1,
892 						 cgraph_edge *edge2, void *data)
893 {
894   fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
895   T *edge1_summary = NULL;
896 
897   if (summary->m_initialize_when_cloning)
898     edge1_summary = summary->get_create (edge1);
899   else
900     edge1_summary = summary->get (edge1);
901 
902   if (edge1_summary)
903     {
904       T *duplicate = summary->get_create (edge2);
905       summary->duplicate (edge1, edge2, edge1_summary, duplicate);
906     }
907 }
908 
909 template <typename T, typename V>
910 inline bool
911 fast_call_summary<T *, V>::is_ggc ()
912 {
913   return is_same<V, va_gc>::value;
914 }
915 
916 template <typename T>
917 void
918 gt_ggc_mx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED)
919 {
920 }
921 
922 template <typename T>
923 void
924 gt_pch_nx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED)
925 {
926 }
927 
928 template <typename T>
929 void
930 gt_pch_nx (fast_call_summary<T *, va_heap>* const& summary ATTRIBUTE_UNUSED,
931 	   gt_pointer_operator op ATTRIBUTE_UNUSED,
932 	   void *cookie ATTRIBUTE_UNUSED)
933 {
934 }
935 
936 template <typename T>
937 void
938 gt_ggc_mx (fast_call_summary<T *, va_gc>* const &summary)
939 {
940   ggc_test_and_set_mark (summary->m_vector);
941   gt_ggc_mx (&summary->m_vector);
942 }
943 
944 template <typename T>
945 void
946 gt_pch_nx (fast_call_summary<T *, va_gc> *const &)
947 {
948   gcc_unreachable ();
949 }
950 
951 template <typename T>
952 void
953 gt_pch_nx (fast_call_summary<T *, va_gc> *const &, gt_pointer_operator, void *)
954 {
955   gcc_unreachable ();
956 }
957 
958 #endif  /* GCC_SYMBOL_SUMMARY_H  */
959